Die Frage ist unten fett gedruckt, das Problem wird auch durch das Destillationscodefragment gegen Ende zusammengefasst.
Ich versuche, mein Typsystem (das Typsystem wechselt vom Typ zum String) zu einer einzigen Komponente (wie von Lakos definiert) zu vereinheitlichen. Ich benutze boost::array
, boost::variant
und boost::mpl
, um dies zu erreichen. Ich möchte die Parser- und Generatorregeln für meine Typen in einer Variante vereinheitlichen. Es gibt einen undefinierten Typ, einen int4-Typ (siehe unten) und einen int8-Typ. Die Variante lautet wie folgt variant<undefined, int4,int8>
.
int4 Merkmale:
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;
};
Die obige Variante beginnt als undefiniert, und dann initialisiere ich die Regeln. Ich hatte ein Problem, das 50 Seiten Fehler verursachte, und ich habe es endlich geschafft, es aufzuspüren, das Variant operator=
während der Zuweisung verwendet und a boost::spirit::qi::int_parser<>
kann keinem anderen zugewiesen werden (operator =).
Im Gegensatz dazu habe ich kein Problem mit meinem undefinierten Typ:
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;
};
Destillation des Problems:
#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();
}
Es gibt eine semantische Lücke zwischen konkreten Parsern und Regeln. Mein Gehirn raucht im Moment, also werde ich nicht über Pramatismus nachdenken. Meine Frage ist, wie löse ich dieses Problem? Ich kann mir drei Ansätze vorstellen, um das Problem zu lösen.
eins: Statische Funktionsmitglieder:
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;
}
};
Ich denke, Ansatz eins verhindert Thread-sicheren Code? ?
zweitens: Der integrale Parser wird in einen shared_ptr eingeschlossen. Es gibt zwei Gründe, warum ich mich mit TMP für das Schreibsystem beschäftige: 1 Effizienz, 2 Zentralisierung von Bedenken in Komponenten. Die Verwendung von Zeigern besiegt den ersten Grund.
Drei: Operator = ist als No-Op definiert. Variante garantiert, dass die lhs
vor der Zuweisung standardmäßig erstellt wird.
Bearbeiten: Ich denke, Option 3 ist am sinnvollsten (Operator = ist ein No-Op). Sobald der Regelcontainer erstellt wurde, ändert er sich nicht mehr, und ich weise nur zu, das Regelmerkmal eines Typs in seinen Versatz zu zwingen.
parser_int32_t
Status hat und eine Referenz verwendet wird. Wenn es zustandslos ist oder eine Kopie erstellt wird, ist es sicher. Aus der Semantik würde ich sagen, dass eine Kopie gemacht wird.