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.
quelle
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..alias()
verwendet wird.Antworten:
Ich bin mir nicht sicher, ob ich das volle Ausmaß der Frage verstehe, aber hier sind ein paar Hinweise
Die mit
// THIS is what I need to do.
Kompilierungen kommentierte Zeile passt gut zu mir (Problem gelöst? Ich vermute, Sie meinten tatsächlich, einen Parser zuzuweisen, keine Regel?)Die Initialisierung von function-local
static
wurde im neuesten Standard (C ++ 11) als threadsicher definiert. Überprüfen Sie die Compiler-Unterstützung für C ++ 0x-Threading. (Wenn der Initialisierer auslöst, versucht ein Durchlauf der Initialisierungsanweisung übrigens erneut zu initialisieren).Regeln
alias()
Wie unter http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases beschrieben
Sie können 'logische Kopien' von Regeln erstellen, ohne den Proto-Ausdruck tatsächlich kopieren zu müssen. Wie in den FAQ angegeben, dient dies hauptsächlich dazu, eine verzögerte Bindung zu ermöglichen
Der Nabialek-Trick könnte genau das sein, was Sie brauchen. Im Grunde wählt er träge einen Parser für die nachfolgende Analyse aus
one = id; two = id >> ',' >> id; keyword.add ("one", &one) ("two", &two) ; start = *(keyword[_a = _1] >> lazy(*_a));
In Ihrem Kontext könnte ich
keyword
definiert sehen alsqi::symbols<char, qi::rule<Iterator>*> keyword;
die ganze Arbeit mit Attributen aus semantischen Aktionen erledigen. Alternative,
qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;
Bringen Sie die Regeln unter den gleichen Typ (wie in der vorherigen Zeile gezeigt).
Dies ist der Teil, in dem ich verwirrt bin: Sie sagen, Sie möchten Ihr Typsystem vereinheitlichen. Möglicherweise sind keine stark typisierten Parser (eindeutige Attributsignaturen) erforderlich.
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;
quelle