Pytanie jest pogrubione u dołu, problem jest również podsumowany fragmentem kodu destylacji pod koniec.
Próbuję ujednolicić mój system typów (system typów robi do i od typu do ciągu) w jeden komponent (zgodnie z definicją Lakos). Używam boost::array
, boost::variant
oraz boost::mpl
w celu osiągnięcia tego celu. Chcę, aby reguły parsera i generatora dla moich typów były ujednolicone w wariancie. istnieje niezdefiniowany typ, typ int4 (patrz poniżej) i typ int8. Wariant ma postać variant<undefined, int4,int8>
.
cechy 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;
};
powyższy wariant zaczyna się jako niezdefiniowany, a następnie inicjuję reguły. Miałem problem, który spowodował 50 stron błędów i w końcu udało mi się go wyśledzić, Variant używa operator=
podczas przypisywania, a boost::spirit::qi::int_parser<>
nie można przypisać do innego (operator =).
Dla kontrastu, nie mam problemu z moim niezdefiniowanym typem:
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;
};
Destylacja problemu:
#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();
}
Istnieje semantyczna luka między konkretnymi parserami a regułami. Mój mózg w tej chwili pali, więc nie zamierzam myśleć o pramatyzmie. Moje pytanie brzmi: jak rozwiązać ten problem? Przychodzą mi do głowy trzy podejścia do rozwiązania problemu.
one: Statyczne składowe funkcji:
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;
}
};
Wydaje mi się, że pierwsze podejście zapobiega kodowi bezpiecznemu wątkowo? ?
dwa: integralny parser jest opakowany w shared_ptr. Są dwa powody, dla których zawracam sobie głowę TMP dla systemu pisania: 1 wydajność, 2 centralizacja problemów na komponenty. używanie wskaźników obala pierwszy powód.
trzy: operator = jest zdefiniowany jako brak działania. wariant gwarantuje, że lhs
jest domyślnie skonstruowany przed przypisaniem.
Edycja: Myślę, że opcja 3 ma największy sens (operator = nie działa). Po utworzeniu kontenera reguł nie zmieni się, a ja przypisuję tylko po to, aby wymusić przesunięcie cechy reguły typu.
źródło
parser_int32_t
ma stan i pobierane jest odwołanie. Jeśli jest bezpaństwowcem lub została wykonana kopia, jest to bezpieczne. Z semantyki powiedziałbym, że kopia jest zrobiona..alias()
jest używana.Odpowiedzi:
Nie jestem pewien, czy w pełni zrozumiałem pytanie, ale oto kilka wskazówek
Wiersz z komentarzem
// THIS is what I need to do.
kompiluje się dobrze ze mną (problem rozwiązany? Domyślam się, że chodziło ci o przypisanie parsera, a nie reguły?)Inicjalizacja funkcji lokalnej
static
została zdefiniowana jako bezpieczna wątkowo w najnowszym standardzie (C ++ 11). Sprawdź, czy Twój kompilator obsługuje wątki C ++ 0x. (Nawiasem mówiąc, jeśli inicjator zgłasza, przekazanie instrukcji inicjalizacji spowoduje ponowną próbę zainicjowania).zasady
alias()
Jak opisano w http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases
Możesz tworzyć „logiczne kopie” reguł bez konieczności kopiowania wartości-wyrażenia proto. Jak mówi FAQ, ma to głównie na celu umożliwienie leniwego wiązania
Nabiałek sztuczka może być dokładnie to, czego potrzebujesz, w zasadzie to leniwie wybiera parser dla późniejszej analizy składniowej
one = id; two = id >> ',' >> id; keyword.add ("one", &one) ("two", &two) ; start = *(keyword[_a = _1] >> lazy(*_a));
W twoim kontekście mógłbym
keyword
zdefiniować jakoqi::symbols<char, qi::rule<Iterator>*> keyword;
wykonanie całej pracy z atrybutami z działań semantycznych. Alternatywnie,
qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;
Doprowadź reguły do tego samego typu (jak pokazano w poprzednim wierszu, w zasadzie)
To jest ta część, w której jestem zdezorientowany: mówisz, że chcesz ujednolicić swój system typów. Może nie być potrzeby stosowania silnych parserów (odrębnych podpisów atrybutów).
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;
źródło