Как получить доступ к элементам boost :: option из правила Spirit :: Qi? - PullRequest
4 голосов
/ 22 февраля 2011

Я не могу найти правильный способ, как получить доступ к членам boost :: Вариант, используя boost :: phoenix в моей грамматике Spirit-Qi. Вот простой пример того, чего я пытаюсь достичь. (вся моя грамматика намного сложнее, это простой фрагмент, где я тестирую упомянутую проблему).

namespace ph = boost::phoenix;
typedef boost::variant<std::string,int> VariantType;
typedef std::list<VariantType> TlstVariants;

rule<Iterator, void(TlstVariants&), Skipper>    rule1;

rule1 = 
   qi::eps [ ph::push_back(qi::_r1, ph::construct<int>(2)) ]
>> qi::eps [ ph::get<int>(ph::back(qi::_r1)) = ph::val(3) ] //THIS IS EXAMPLE OF WHAT I NEED
;

TlstVariants lstVals;
ExecuteParser("5",rule1( ph::ref(lstVals) ));   

BOOST_FOREACH( VariantType &val, lstVals )
{
    std::cout << val.which() << " - " << val;
}

Но я не могу найти ни один phoenix :: get <> или какой-либо подобный метод для доступа к boost :: варианту с помощью Phoenix. Причина, по которой мне нужен phoenix :: get <>, заключается в том, что мне нужно вставить вариант в список с определенным типом, а затем передать этот конкретный тип как ссылку на дочернее правило в качестве унаследованного атрибута:

qi::rule<Iterator, void(structTest&), Skipper> rule_child;

rule = 
  qi::lit("test") [ph::push_back(sp::_r1, ph::construct<structTest>())]
> qi::lit('(') 
> rule_child( ph::get<structTest>(ph::back(sp::_r1)) ) 
> qi::lit(')') 
...

Есть ли способ, как добиться такого поведения?

Спасибо за любой ответ

Rick

Ответы [ 2 ]

3 голосов
/ 22 февраля 2011

Довольно легко написать собственную «ленивую» функцию Phoenix. Вот один для boost::variant.

#include <boost/variant.hpp>
#include <boost/spirit/include/phoenix.hpp>

template <typename Result>
struct get_impl
{
    template <typename T>
    struct result
    {
        typedef Result type;
    };

    template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
    Result operator()(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& v) const
    {
        return boost::get<Result>(v);
    }
};

ph::function<get_impl<int> > const get_int = get_impl<int>();

Теперь это можно использовать в семантическом действии:

... qi::eps [ get_int(ph::back(qi::_r1)) = ph::val(3) ]
1 голос
/ 22 февраля 2011

Я думаю, что нашел способ, как это сделать. (Не знаю, если это лучший способ, но это работает ;-)). Проблема была в int & type, потому что boost :: variable содержит int, а не int &. Поэтому я обновляю ваш шаблон, чтобы принимать два типа: один для варианта получения и один для типа возврата.

Я обновил get_impl шаблон таким образом:

template <typename Result, typename Inner>
struct get_impl
{
    template <typename T>
    struct result
    {
        typedef Result type;
    };

    template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
    Result operator()(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & v) const
    {
        return boost::get<Inner>(v);
    }
};

И моя грамматика теперь выглядит так:

typedef boost::variant<std::string,int> VariantType;
qi::rule<DG_Iterator, void(VariantType&), DG_Skipper>   rule1;

ph::function<get_impl<int,int> >  const get_int = get_impl<int, int>();
ph::function<get_impl<int&,int> > const get_int_ref = get_impl<int&,int>();

rule1 = 
    qi::eps [ std::cout << ph::val("variant=") << qi::_r1 << ph::val("\n") ]
>> qi::eps [ std::cout << ph::val("before=") << get_int(qi::_r1) << ph::val("\n") ]
>> qi::eps [ get_int_ref(qi::_r1) = ph::val(7) ]
>> qi::eps [ std::cout << ph::val("after=") << get_int(qi::_r1) << ph::val("\n") ]
;

VariantType val(2134);
TestSimpleRuleValidity("x",rule1( ph::ref(val) ), true);    
std::cout << val << "\n";

И все, кажется, работает хорошо. Еще раз спасибо hkaiser за ваш первоначальный ответ, который мне очень помогает.

...