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.
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.