Больше безумства духа - парсер-типы (правила против int_parser <>) и методы метапрограммирования
Вопрос выделен жирным шрифтом внизу, проблема также суммируется фрагментом кода дистилляции в конце.
Я пытаюсь унифицировать мою систему типов (система типов делает из и от типа к строке) в один компонент (как определено Lakos). Для этого я использую boost::array
, boost::variant
и boost::mpl
. Я хочу иметь правила парсера и генератора для моих типов, унифицированных в одном варианте. существует тип undefined, тип 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;
};
вариант выше начинается как undefined, а затем я инициализирую правила. У меня возникла проблема, которая вызвала 50 страниц ошибок, и мне, наконец, удалось ее отслеживать, Variant использует operator=
во время назначения, а boost::spirit::qi::int_parser<>
не может быть назначен другому (operator =).
Для сравнения, у меня нет проблемы с типом undefined:
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 централизация проблем в компонентах. использование указателей поражает первую причину.
три: operator = определяется как no-op. вариант гарантирует, что lhs
по умолчанию сконфигурирован перед назначением.
Edit:
Я думаю, что вариант 3 имеет наибольший смысл (operator = is no-op). Как только контейнер правил будет создан, он не изменится, и я только назначаю, чтобы заставить свойство правила типа в его смещение.
Ответы
Ответ 1
Я не уверен, что меня полностью интересует вопрос, но вот несколько советов
-
Строка, прокомментированная с помощью // THIS is what I need to do.
, компилируется со мной (проблема решена? Я предполагаю, что вы на самом деле подразумевали назначение синтаксического анализатора, а не правила?)
-
Инициализация функции-local static
была определена как потокобезопасная в последнем стандарте (С++ 11). Проверьте поддержку компилятора для потоковой передачи С++ 0x. (Если инициализатор выбрасывает, провал инициализации будет пытаться инициализировать снова, кстати).
-
правила alias()
Как описано в http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases
Вы можете создать "логические копии" правил без фактического значения копирования прото-выражения. Как часто задают вопросы, это в основном для обеспечения ленивого связывания
-
Nabialek Trick может быть именно тем, что вам нужно, в основном это лениво выбирает парсер для последующего разбора
one = id;
two = id >> ',' >> id;
keyword.add
("one", &one)
("two", &two)
;
start = *(keyword[_a = _1] >> lazy(*_a));
В вашем контексте я мог видеть keyword
, определенный как
qi::symbols<char, qi::rule<Iterator>*> keyword;
выполняет всю работу с атрибутами из семантических действий. В качестве альтернативы,
qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;
-
Приведите правила под одним и тем же типом (как показано в предыдущей строке, в основном)
Это та часть, где я запутался: вы говорите, что хотите унифицировать свою систему типов. Возможно, не требуется синтаксический синтаксический анализатор (различные атрибутные атрибуты).
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;