80

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

我正在尝试将我的类型系统(类型系统从类型到字符串)统一到一个组件中(由 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;
    };

上面的变体一开始是未定义的,然后我初始化了规则。我遇到了一个问题,导致了 50 页的错误,我终于设法找到了它,Variantoperator=在分配过程中使用,aboost::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;
    };

问题的蒸馏:

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

具体解析器和规则之间存在语义鸿沟。我的大脑现在在冒烟,所以我不会考虑实用主义,我的问题是,我该如何解决这个问题? 我可以想到三种解决问题的方法。

一:静态函数成员:

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

我猜方法一会阻止线程安全代码??

二:整体解析器被包裹在一个shared_ptr中。我为打字系统使用 TMP 有两个原因:1 效率,2 将关注点集中到组件中。使用指针打败了第一个原因。

三: operator=被定义为无操作。变体保证lhs在赋值之前默认构造。

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

4

1 回答 1

11

我不太确定我得到了问题的全部内容,但这里有一些提示

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

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

  • 规则alias()

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

    您可以创建规则的“逻辑副本”,而无需实际对原始表达式进行值复制。正如FAQ所说,这主要是为了允许延迟绑定

  • Nabialek Trick可能正是您所需要的,基本上它会懒惰地选择一个解析器进行后续解析

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

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

    qi::symbols<char, qi::rule<Iterator>*> keyword;
    

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

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

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

    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;
    
于 2012-02-02T09:34:35.160 回答