La pregunta está en negrita en la parte inferior, el problema también se resume en el fragmento de código de destilación hacia el final.
Estoy tratando de unificar mi sistema de tipos (el sistema de tipos hace y de un tipo a una cadena) en un solo componente (como lo define Lakos). Estoy usando boost::array
, boost::variant
y boost::mpl
, para lograr esto. Quiero tener las reglas del analizador y del generador para mis tipos unificadas en una variante. hay un tipo indefinido, un tipo int4 (ver más abajo) y un tipo int8. La variante se lee como variant<undefined, int4,int8>
.
rasgos int4:
struct rbl_int4_parser_rule_definition
{
typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;
boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;
rule_type rule;
rbl_int4_parser_rule_definition()
{
rule.name("rbl int4 rule");
rule = parser_int32_t;
}
};
template<>
struct rbl_type_parser_rule<rbl_int4>
{
typedef rbl_int4_parser_rule_definition string_parser;
};
la variante anterior comienza como indefinida y luego inicializo las reglas. Tuve un problema, que causó 50 páginas de errores, y finalmente logré rastrearlo, los usos de Variant operator=
durante la asignación y boost::spirit::qi::int_parser<>
no se pueden asignar a otro (operator =).
En contraste, no tengo ningún problema con mi tipo indefinido:
struct rbl_undefined_parser_rule_definition
{
typedef boost::spirit::qi::rule<std::string::iterator, void()> rule_type;
rule_type rule;
rbl_undefined_parser_rule_definition()
{
rule.name("undefined parse rule");
rule = boost::spirit::qi::eps;
}
};
template<>
struct rbl_type_parser_rule<rbl_undefined>
{
typedef rbl_undefined_parser_rule_definition string_parser;
};
Destilación del problema:
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/variant.hpp>
#include <boost/cstdint.hpp>
typedef boost::spirit::qi::rule<std::string::iterator,void()> r1;
typedef boost::spirit::qi::rule<std::string::iterator,int()> r2;
typedef boost::variant<r1,r2> v;
int main()
{
/*
problematic
boost::spirit::qi::int_parser<int32_t> t2;
boost::spirit::qi::int_parser<int32_t> t1;
t1 = t2;
*/
//unproblematic
r1 r1_;
r2 r2_;
r1_ = r2_;
v v_;
// THIS is what I need to do.
v_ = r2();
}
Existe una brecha semántica entre los analizadores concretos y las reglas. Mi cerebro está fumando en este momento, así que no voy a pensar en el pramatismo. Mi pregunta es, ¿cómo soluciono este problema? Puedo pensar en tres enfoques para resolver el problema.
uno: miembros de la función estática:
struct rbl_int4_parser_rule_definition
{
typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;
//boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;
rule_type rule;
rbl_int4_parser_rule_definition()
{
static boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;
rule.name("rbl int4 rule");
rule = parser_int32_t;
}
};
¿Supongo que el enfoque uno previene el código seguro para subprocesos? ?
dos: el analizador integral está envuelto en un shared_ptr. Hay dos razones por las que me molesto con TMP para el sistema de mecanografía: 1 eficiencia, 2 preocupaciones de centralización en componentes. el uso de punteros anula la primera razón.
tres: operador = se define como no operativo. La variante garantiza que lhs
se construye por defecto antes de la asignación.
Editar: Estoy pensando que la opción 3 tiene más sentido (operador = no es una operación). Una vez que se crea el contenedor de reglas, no cambiará, y solo estoy asignando para forzar el rasgo de regla de un tipo en su desplazamiento.
parser_int32_t
tiene un estado y se toma una referencia. Si es apátrida o se hace una copia, entonces es seguro. Desde la semántica, diría que se hace una copia.