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.
fuente
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..alias()
se use.Respuestas:
No estoy tan seguro de entender todo el alcance de la pregunta, pero aquí hay algunas sugerencias
La línea comentada con se
// THIS is what I need to do.
compila bien para mí (¿problema resuelto? Supongo que en realidad se refería a asignar un analizador, no una regla).La inicialización de la función local
static
se ha definido para que sea segura para subprocesos en el último estándar (C ++ 11). Compruebe el soporte de su compilador para subprocesos C ++ 0x. (Si el inicializador arroja, una pasada de la instrucción de inicialización intentará inicializar nuevamente, por cierto).reglas
alias()
Como se describe en http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases
Puede crear 'copias lógicas' de reglas sin tener que copiar valores de la protoexpresión. Como dice la pregunta frecuente, esto es principalmente para permitir el enlace diferido
El truco de Nabialek puede ser precisamente lo que necesita, básicamente, selecciona un analizador para el análisis posterior.
one = id; two = id >> ',' >> id; keyword.add ("one", &one) ("two", &two) ; start = *(keyword[_a = _1] >> lazy(*_a));
En su contexto, podría ver
keyword
definido comoqi::symbols<char, qi::rule<Iterator>*> keyword;
haciendo todo el trabajo con atributos de acciones semánticas. Alternativamente,
qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;
Traiga las reglas del mismo tipo (como se muestra en la línea anterior, básicamente)
Esta es la parte en la que me confundo: dice que quiere unificar su sistema de tipos. Puede que no sea necesario utilizar analizadores de tipo fuerte (firmas de atributos distintos).
typedef boost::variant<std::string,int> unified_type; typedef qi::rule<std::string::iterator, unified_type() > unified_rule; unified_rule rstring = +(qi::char_ - '.'); unified_rule rint = qi::int_; unified_rule combine = rstring | rint;
fuente