【问题标题】:How to access boost::variant members from Spirit::Qi rule?如何从 Spirit::Qi 规则访问 boost::variant 成员?
【发布时间】:2011-02-22 10:39:07
【问题描述】:

在我的 Spirit-Qi 语法中,我找不到如何使用 boost::phoenix 访问 boost::variant 成员的正确方法。这是我想要实现的简单示例。 (我的整个语法要复杂得多,这是我正在测试提到的问题的简单片段)。

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 或任何类似的方法来使用 Phoenix 访问 boost::variant。我需要 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(')') 
...

有没有办法实现这样的行为?

感谢您的回复

瑞克

【问题讨论】:

    标签: c++ boost boost-spirit boost-spirit-qi boost-phoenix


    【解决方案1】:

    编写自己的“惰性”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) ]
    

    【讨论】:

    • 感谢您的回复。由于源代码格式化,我必须将我的评论作为我自己的回复发表。
    • 还是那样做吗?这么常见的操作不属于库的一部分,这似乎很奇怪?
    【解决方案2】:

    我想我找到了一种方法。 (不知道这是否是最好的方法,但它有效;-))。 问题在于 int& 类型,因为 boost::variant 包含 int 而不是 int&。因此,我更新了您的模板以接受两种类型,一种用于变体 getter,另一种用于返回类型。

    我以这种方式更新了 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 最初的回复,这对我很有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多