如何从 Spirit::Qi 规则访问 boost::variant 成员?

发布于 2024-10-18 16:30:06 字数 1214 浏览 6 评论 0原文

我无法找到如何在我的 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(')') 
...

有什么方法可以实现这样的行为吗?

感谢您的回复

瑞克

I can't find a proper way how to access members of boost::variant using boost::phoenix in my Spirit-Qi grammar. Here is simple an example what I’m trying to achieve. (my whole grammar is much more complex, this is simple fragment where I'm testing mentioned problem).

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;
}

But I can't find any phoenix::get<> or any similar method to access boost::variant using Phoenix. Reason why I need phoenix::get<> is because I need to insert variant to list with specific type and then pass this specific type as reference to the child rule as inherited attribute:

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(')') 
...

Is there any way how to achieve behavior like this?

Thank for any reply

Rick

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

桜花祭 2024-10-25 16:30:06

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

It's fairly easy to write your own 'lazy' Phoenix function. Here is one for 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>();

Now, this can be used in a semantic action:

... qi::eps [ get_int(ph::back(qi::_r1)) = ph::val(3) ]
瞄了个咪的 2024-10-25 16:30:06

我想我找到了一种方法。 (不知道这是否是最好的方法,但它有效;-))。
问题出在 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的最初回复,这对我帮助很大。

I think I found a way how to do it. (Don't know if this is best way, but it works ;-) ).
The problem was in int& type, because boost::variant holds int and not int&. So I update your template to accept two types, one for variant getter and one for return type.

I updated get_impl template in this way:

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);
    }
};

And my grammar now looks like this:

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";

And everything seems to works Ok. Thank you again hkaiser for your initial reply which helps me a lot.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文