更多精神疯狂 - 解析器类型(规则与int_parser <>)和元编程技术

Has*_*yed 80 c++ boost boost-spirit template-meta-programming

问题在底部以粗体显示,问题也通过最终的蒸馏代码片段进行了总结.

我试图统一我的类型系统(类型系统从类型到字符串)和单个组件(由Lakos定义).我正在使用boost::array,, boost::variantboost::mpl,以实现这一目标.我想让我的类型的解析器和生成器规则统一在一个变体中.有一个未定义的类型,一个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;
};
Run Code Online (Sandbox Code Playgroud)

上面的变体从未定义开始,然后我初始化规则.我有一个问题,导致50页的错误,我终于设法跟踪它,Variant operator=在分配期间使用,而a boost::spirit::qi::int_parser<>不能分配给另一个(operator =).

相比之下,我的未定义类型没有问题:

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;
};
Run Code Online (Sandbox Code Playgroud)

蒸馏问题:

#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();
}
Run Code Online (Sandbox Code Playgroud)

具体的解析器和规则之间存在语义上的差距.我的大脑此刻正在抽烟,所以我不会考虑使用感觉,我的问题是,我该如何解决这个问题呢? 我可以想出解决问题的三种方法.

一:静态功能成员:

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;  
  }
};
Run Code Online (Sandbox Code Playgroud)

我想方法一可以防止线程安全的代码??

二:整数解析器包装在shared_ptr中.有两个原因我打扰了打字系统的TMP:1效率,2集中关注组件.使用指针击败了第一个原因.

三: operator =被定义为no-op.variant保证lhs在赋值之前默认构造.

编辑: 我认为选项3最有意义(operator =是无操作).一旦创建了规则容器,它就不会改变,我只是指定强制类型的规则特征到它的偏移量.

seh*_*ehe 11

我不太确定我是否完全接受了这个问题,但这里有一些提示

  • 这行注释与// THIS is what I need to do.我编译好(问题解决了?我猜你实际上是指分配一个解析器,而不是一个规则?)

  • 函数local的初始化static在最新标准(C++ 11)中被定义为线程安全.检查编译器对C++ 0x线程的支持.(如果初始化程序抛出,那么初始化语句的传递将尝试再次初始化).

  • 规则 alias()

    http://boost-spirit.com/home/articles/doc-addendum/faq/#aliases中所述

    您可以创建规则的"逻辑副本",而无需实际值复制proto表达式.正如FAQ所说,这主要是为了允许延迟绑定

  • Nabialek伎俩可能正是你所需要的,基本上它懒洋洋地选择后续解析解析器

    one = id;
    two = id >> ',' >> id;
    
    keyword.add
        ("one", &one)
        ("two", &two)
        ;
    
    start = *(keyword[_a = _1] >> lazy(*_a));
    
    Run Code Online (Sandbox Code Playgroud)

    在您的上下文中,我可以看到keyword定义为

    qi::symbols<char, qi::rule<Iterator>*> keyword;
    
    Run Code Online (Sandbox Code Playgroud)

    使用语义操作的属性完成所有工作.或者,

    qi::symbols<char, qi::rule<Iterator, std::variant<std::string,int>() >*> keyword;
    
    Run Code Online (Sandbox Code Playgroud)
  • 将规则置于相同类型下(如上一行所示,基本上)

    这是我感到困惑的部分:你说你想要统一你的类型系统.可能不需要强类型解析器(不同的属性签名).

    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;
    
    Run Code Online (Sandbox Code Playgroud)