更多的精神错乱-解析器类型(规则 vs int_parser < >)和元编程技术

问题是在底部以粗体显示的,问题也是由蒸馏代码片段总结到最后的。

我试图将我的类型系统(类型系统在类型和字符串之间进行转换)统一为单个组件(如 Lakos 所定义的那样)。我正在使用 boost::arrayboost::variantboost::mpl,为了实现这一点。我希望将类型的解析器和生成器规则统一在一个变体中。有一个未定义的类型,一个 int4(见下文)类型和一个 int8类型。变体读取为 variant<undefined, int4,int8>

返回文章页面特点:

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

the variant above starts out as undefined, and then I initialize the rules. I had a problem, which caused 50 pages of errors, and I have finally managed to track it down, Variant uses operator= during assignment and a boost::spirit::qi::int_parser<> cannot be assigned to another (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;
}
};

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

第二: 整数解析器封装在 share _ ptr 中。我为打字系统使用 TMP 有两个原因: 1效率,2将关注点集中到组件中。使用指针击败了第一个原因。

三: 操作符 = 被定义为 no-op。

编辑: 我认为选项3是最有意义的(操作符 = 是不可操作的)。一旦规则容器被创建,它将不会改变,我只是分配强制类型的规则特性到它的偏移量。

3946 次浏览

我不确定自己是否了解了问题的全部内容,但这里有一些提示

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

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

  • 规则 alias()

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

    您可以创建规则的“逻辑副本”,而不必实际复制原型表达式的值。正如常见问题解答所说,这主要是为了允许延迟绑定

  • Nabialek 魔术可能正是您所需要的,基本上它懒惰地选择一个解析器用于后续解析

    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;
    
  • Bring the rules under the same type (like shown in the previous line, basically)

    This is the part where I'm getting confused: You say you want to unify your type system. There might not be a need for strongtyped parsers (distinct attribute signatures).

    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;