【问题标题】:boost spirit karma generating based on class inputs提升基于职业输入的精神业力生成
【发布时间】:2013-02-22 10:52:56
【问题描述】:

嗨,我想要的是根据我传递给生成器的内容生成一些文本,例如

struct C1
{
    int Getter()
    {
        return 3;
    }
};

struct C2
{
    int Getter()
    {
        return 5;
    }
};




template<typename Iterator>
struct Temp:
    public karma::grammar<Iterator,boost::variant<C1*,C2*>()>
{
    Temp():
        Temp::base_type(start1)
    {
        using karma::int_;
        using karma::float_;
        using karma::lit;

        start1 = c1 | c2;
        c1 = karma::lazy(boost::phoenix::bind(&C1::Getter,karma::_1));
        c2 = karma::lazy(boost::phoenix::bind(&C2::Getter,karma::_1));

    }

    karma::rule<Iterator,boost::variant<C1*,C2*>()> start1;
    karma::rule<Iterator,C1*() > c1;
    karma::rule<Iterator,C2*() > c2;

... 然后调用类似

std::string str;
std::back_insert_iterator<std::string> out(str);
Temp<std::back_insert_iterator<std::string> > bla;
C1 c1;
karma::generate(out, bla,&c1);

我什至不确定我是否使用了正确的生成器,但它说惰性能够从属性中的内容转换为返回内部函子的内容

【问题讨论】:

  • karma::lazy 要求其参数评估为生成器对象,因此您尝试的操作将不起作用。您只需要使用semantic actions
  • 我大大扩展了我的答案,展示了基于BOOST_FUSION_ADAPT_ADT的两种方法

标签: c++ boost lazy-evaluation boost-spirit boost-spirit-karma


【解决方案1】:

最简单的解决办法是

c1 = int_ [ karma::_1 = boost::phoenix::bind(&C1::Getter,karma::_val) ];
c2 = int_ [ karma::_1 = boost::phoenix::bind(&C2::Getter,karma::_val) ];

BOOST_FUSION_ADAPT_ADT

我想你也想了解BOOST_FUSION_ADAPT_ADT()

struct C1 { int Getter() const { return 3; } void Setter(int){} }; 
struct C2 { int Getter() const { return 5; } void Setter(int){} }; 

BOOST_FUSION_ADAPT_ADT(C1, (int,int,obj.Getter(),obj.Setter(val)));
BOOST_FUSION_ADAPT_ADT(C2, (int,int,obj.Getter(),obj.Setter(val)));

备选方案 1:attr_cast

使用attr_cast 并按值传递。为简洁起见,这是一个没有语法的示例:

using namespace karma;
std::cout << karma::format("C1:" << attr_cast<C1>(int_) | "C2:" << attr_cast<C2>(int_), c1) << "\n";
std::cout << karma::format("C1:" << attr_cast<C1>(int_) | "C2:" << attr_cast<C2>(int_), c2) << "\n";

打印出来的

C1:3
C2:5

备选方案 2:使用语法/规则

typedef boost::variant<C1,C2> Var;

template<typename Iterator>
struct Generator: public karma::grammar<Iterator,Var()>
{
    Generator(): Generator::base_type(start)
    {
        using namespace karma;

        start = "grammar: " << (c1 | c2);
        c1 = "C1:" << attr_cast<int>(int_);
        c2 = "C2:" << attr_cast<int>(int_);
    }

  private:
    karma::rule<Iterator,Var()> start;
    karma::rule<Iterator,C1()> c1;
    karma::rule<Iterator,C2()> c2;
};

这里有一个完整的示例,显示了这两种替代方案:http://liveworkspace.org/code/JWB9B$0

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

struct C1 { int Getter() const { return 3; } void Setter(int){} }; 
struct C2 { int Getter() const { return 5; } void Setter(int){} }; 

BOOST_FUSION_ADAPT_ADT(C1, (int,int,obj.Getter(),obj.Setter(val)));
BOOST_FUSION_ADAPT_ADT(C2, (int,int,obj.Getter(),obj.Setter(val)));

typedef boost::variant<C1,C2> Var;

template<typename Iterator>
struct Generator: public karma::grammar<Iterator,Var()>
{
    Generator(): Generator::base_type(start)
    {
        using namespace karma;

        start = "grammar: " << (c1 | c2);
        c1 = "C1:" << attr_cast<int>(int_);
        c2 = "C2:" << attr_cast<int>(int_);
    }

  private:
    karma::rule<Iterator,Var()> start;
    karma::rule<Iterator,C1()> c1;
    karma::rule<Iterator,C2()> c2;
};

typedef boost::spirit::ostream_iterator It;

int main()
{
    C1 c1;
    C2 c2;

    using namespace karma;
    std::cout << karma::format("C1:" << attr_cast<C1>(int_) | "C2:" << attr_cast<C2>(int_), c1) << "\n";
    std::cout << karma::format("C1:" << attr_cast<C1>(int_) | "C2:" << attr_cast<C2>(int_), c2) << "\n";

    // or using a grammar:
    Generator<It> bla;
    std::cout << karma::format(bla, Var(c1)) << "\n";
    std::cout << karma::format(bla, Var(c2)) << "\n";
}

【讨论】:

  • attr_cast 是什么让您可以回避here 描述的本地参考问题?
  • @llonesmiz 是的。我今天“重新发现”了这个限制(错误),这导致我最初没有发布它的例子:)。我已经知道很长一段时间了(我是跟踪器中的错误sehe)。 AFAICT attr_cast 确实可以防止麻烦,既与单元素融合序列适配器有关,也与本地参考问题有关。我听说 Spirit X3 属性处理修复了大多数棘手的情况,并承诺更加一致,您可以在 this interesting conversation 中找到。
  • 本质似乎是attr_cast将属性消耗与代理评估分开,代价是1个显式属性副本。
  • 非常有趣。一如既往地感谢您的回答。比起使用语义动作,我更喜欢这种解决问题的方法。
  • @llonesmiz 同样,先生!你教会了我很多。 Cheers!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多