检测 Spirit 语义动作中的参数类型

2021-12-31 00:00:00 compiler-errors c++ boost-spirit

一般情况:我不明白为什么我的 Spirit 语法/语义动作没有编译.

General case: I can't figure out why my Spirit grammar/semantics actions aren't compiling.

有时,编译器会抱怨赋值或类型不兼容,我不知道出了什么问题.问题主要出现在两个方面:

Sometimes, the compiler will complain about assignment or type incompatibilities and I have no clue what's wrong. The problem occurs in two main areas:

  • 预测规则/表达式的综合属性类型
    • 因此,预测哪些类型的属性可以合法地定义为规则的公开属性(依赖于内置转换、融合适配器或 Spirit 自定义点)
    • 编译器将能够编译函数调用
    • 调用不会在过程中调用不必要的隐式转换

    编译器错误并不完全易于处理,要么文档有误,要么我误解了它.

    The compiler error is not exactly tractable, and either the documentation is wrong, or I misunderstood it.

    无论如何,有没有办法确切地找出精神传递到我的语义动作中的内容?

    Is there a way to find out exactly what Spirit passes into my semantic action, anyway?

    struct mybase             { int a,b; };
    struct myderived : mybase { int c,d; };
    
    BOOST_FUSION_ADAPT_STRUCT(mybase,    (int,a)(int,b));
    BOOST_FUSION_ADAPT_STRUCT(myderived, (int,a)(int,b)(int,c)(int,d));
    
    auto base_expr = int_ >> int_; // avoids assigning to struct attribute
    
    rule<decltype(f), mybase()   , space_type> base_       = int_ >> int_;
    rule<decltype(f), myderived(), space_type> derived_    = base_ >> int_ >> int_;
    
    myderived data;
    bool ok = phrase_parse(f,l,derived_,space,data);
    

    此代码无法编译,存在大量难以理解的错误.

    This code won't compile, with a huge amount of impenetrable errors.

    (粗略改编自 精神一般列表)

    推荐答案

    为了清楚起见 - 这里的错误是 base_ >>内部_>>int_ 被用作创建 myderived 的规则的表达式,并且由于 base_ 固定为类型 mybase,我们d 必须从 mybase 和两个 int 创建一个 myderrived,但是没有什么可以告诉 Spirit 如何做到这一点.

    For clarity - the error here is that base_ >> int_ >> int_ was used as the expression for a rule that creates a myderived, and since base_ is fixed to type mybase, we'd have to create a myderrived from a mybase and two ints, but there's nothing to tell Spirit how to do that.

    您可以使用 boost 打印出 boost 通过解析 base_ >> 创建的值的类型.内部_>>int_ 通过定义一个可以接受任何参数的函子,并告诉您它们是什么(以下代码改编自 SO chat 上的一些代码):

    You can get boost to print out the type of the value that boost creates from parsing base_ >> int_ >> int_ by defining a functor that will take any parameters, and tell you what they are (the following code is adapted from some code sehe put on SO chat):

    struct what_is_the_attr
    {
        template <typename> struct result { typedef bool type; };
    
        template <typename T>
        static void print_the_type()
        {
            std::cout << "    ";
            std::cout << typeid(T).name();
            if(std::is_const<typename std::remove_reference<T>::type>::value)
                std::cout << " const";
            if(std::is_rvalue_reference<T>::value)
                std::cout << " &&";
            else if(std::is_lvalue_reference<T>::value)
                std::cout << " &";
        }
    
        template <typename Th, typename Th2, typename... Tt>
        static void print_the_type()
        {
            print_the_type<Th>();
            std::cout << ",
    ";
            print_the_type<Th2, Tt...>();
        }
    
        template <typename... Ts>
        void operator()(Ts&&...) const
        {
            std::cout << "what_is_the_attr(
    ";
            print_the_type<Ts...>();
            std::cout << ")" << std::endl;
        }
    };
    

    然后要使用它,请在初始化程序的语义操作中为您的错误规则使用上述角色:

    Then to use it, use the above actor in a semantic action on initializer for your faulty rule:

    std::string input = "1 2 3 4";
    auto f(std::begin(input)), l(std::end(input));
    
    rule<decltype(f), mybase()   , space_type> base_    = int_ >> int_;
    rule<decltype(f), myderived(), space_type> derived_ = (base_ >> int_ >> int_)[what_is_the_attr()];
    
    myderived data;
    bool ok = phrase_parse(f,l,derived_,space,data);
    

    注意,您不能通过 %= 使用自动属性传播(除非您从规则的声明类型中删除了暴露的属性类型).

    Note, you cannot use automatic attribute propagation with %= (unless you remove the exposed attribute type from the rule's declared type).

    运行它应该会产生一个编码类型,可以用 c++filt -t 解码:生活在 Coliru 上

    Running this should then yield an encoded type, which can be decoded with c++filt -t: Live On Coliru

    $ g++ 9404189.cpp -std=c++0x
    $ ./a.out |c++filt -t
    what_is_the_attr(
        boost::fusion::vector3<mybase, int, int> &,
        boost::spirit::context<boost::fusion::cons<boost::spirit::unused_type&, boost::fusion::nil>, boost::fusion::vector0<void> > &,
        bool &)
    

    第一行,boost::fusion::vector3<mybase, int, int>,至少告诉你 boost 正在尝试从 3 个 mybase 类型的对象创建你的返回类型intint.

    The first line, boost::fusion::vector3<mybase, int, int>, least tells you that boost is trying to create your return type from 3 objects of types mybase, int and int.

相关文章