Питання напівжирним шрифтом внизу, проблема також узагальнена фрагментом коду перегонки до кінця.
Я намагаюся об'єднати мою систему типів (система типів робить це і від типу до рядка) в один компонент (як визначено Лакосом). Я використовую boost::array
, boost::variant
і boost::mpl
, для цього. Я хочу, щоб правила синтаксичного аналізу та генератора для моїх типів були уніфіковані у варіанті. існує невизначений тип, тип int4 (див. нижче) та тип int8. Варіант читається як variant<undefined, int4,int8>
.
риси 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;
};
варіант вище починається як невизначений, і тоді я ініціалізую правила. У мене виникла проблема, яка спричинила 50 сторінок помилок, і нарешті мені вдалося її відстежити, Variant використовує operator=
під час призначення, а a boost::spirit::qi::int_parser<>
не може бути призначений іншому (operator =).
На відміну від цього, у мене немає проблем із моїм невизначеним типом:
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;
};
Дистиляція проблеми:
#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();
}
Між конкретними синтаксичними аналізаторами та правилами існує семантичний розрив. Зараз мій мозок курить, тому я не збираюся думати про праматизм. Моє питання полягає в тому, як мені вирішити цю проблему? Я можу придумати три підходи до вирішення проблеми.
one: Статичні члени функції:
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;
}
};
Я думаю, підхід один запобігає потокобезпечний код? ?
друге: цілісний синтаксичний аналізатор обертається у shared_ptr. Є дві причини, за якими я турбуюся про TMP для системи друку: 1 ефективність, 2 централізація проблем на компоненти. використання покажчиків перемагає першу причину.
три: оператор = визначається як не-операція. variant гарантує, що значення за lhs
замовчуванням будується перед призначенням.
Редагувати: Я думаю, варіант 3 має найбільший сенс (оператор = не застосовується). Після створення контейнера з правилами він не зміниться, і я лише призначаю примусити ознаку правила типу до її зміщення.
parser_int32_t
має стан і береться посилання. Якщо без громадянства або зроблена копія, це безпечно. З семантики я б сказав, що зроблена копія.