Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 凤凰城:绑定到C++;boost::spirit::qi语义动作中的11个lambdas_C++_C++11_Lambda_Boost Spirit - Fatal编程技术网

C++ 凤凰城:绑定到C++;boost::spirit::qi语义动作中的11个lambdas

C++ 凤凰城:绑定到C++;boost::spirit::qi语义动作中的11个lambdas,c++,c++11,lambda,boost-spirit,C++,C++11,Lambda,Boost Spirit,我的目标是创建一个变通方法,这样我就可以在Boost Spirit Qi语义操作中使用C++11 lambda,同时仍然可以访问更扩展的Qi占位符集,例如Qi::\u pass或Qi:\u r1,而不必手动从上下文对象中提取它们。我希望避免编写菲尼克斯lambda用于一些非平凡的解析逻辑,更喜欢C++ 11中的更直接的C++语法和语义。 下面的代码代表了我对解决方案的想法。其思想是使用phoenix::bind绑定到lambda,并将我需要的特定占位符传递给它。然而,我得到了一个非常长的模板化编

我的目标是创建一个变通方法,这样我就可以在Boost Spirit Qi语义操作中使用C++11 lambda,同时仍然可以访问更扩展的Qi占位符集,例如Qi::\u pass或Qi:\u r1,而不必手动从上下文对象中提取它们。我希望避免编写菲尼克斯lambda用于一些非平凡的解析逻辑,更喜欢C++ 11中的更直接的C++语法和语义。 下面的代码代表了我对解决方案的想法。其思想是使用phoenix::bind绑定到lambda,并将我需要的特定占位符传递给它。然而,我得到了一个非常长的模板化编译器错误(GCC4.7.0,Boost1.54),我没有专业知识来解释。我选择了我认为最相关的部分,并将其发布在代码下面

我想知道我在这段代码中尝试的操作是否可以通过Boost Spirit实现,是否有人可以为我解释错误消息并告诉我出了什么问题

#include <string>
#include <iostream>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace phoenix = boost::phoenix;

int main() {

    std::string input{"test1 test2 test3 FOO!"};
    typedef decltype(input.begin()) StringIter;

    qi::rule<StringIter, std::string()> parser =
        *(
            qi::char_
            [
                phoenix::bind(
                    [] (char value) {
                        std::cerr << value << std::endl;
                    },
                    qi::_1
                )
            ]
        );

    qi::parse(input.begin(), input.end(), parser);
}
#包括
#包括
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间spirit=boost::spirit;
名称空间phoenix=boost::phoenix;
int main(){
字符串输入{“test1test2test3foo!”;
typedef decltype(input.begin())StringIter;
qi::规则解析器=
*(
qi::char_
[
凤凰:绑定(
[](字符值){
标准:cerr
>
>
) (
boost::spirit::traits::pass\u属性<
boost::spirit::qi::char\u类<
boost::spirit::tag::char\u代码<
boost::spirit::tag::char_
,boost::spirit::char\u编码::标准
>
>,char,void
>::类型&
,boost::spirit::context<
boost::fusion::cons
,boost::fusion::vector0
>嗯,布尔&
)'

只要告诉Boost您需要最先进的编译器支持:[1]

您希望使用Phoenix的V3版本:

#define BOOST_SPIRIT_USE_PHOENIX_V3
它是有效的

查看它

原因:

  • 在Phoenix actors中使用函数对象时,假定函数对象将有一个特殊的嵌套
    结构结果
    模板,或者实际上是一个简单的typedef
    结果类型
    。这称为协议的结果,请参见此处:

    此协议是c++03兼容性所必需的。但是,lambdas没有它。事实上,lambdas具有未指定的类型。这正是支持lambdas的编译器始终具有
    decltype
    的原因之一,因此不再需要协议的结果

  • 在第二个
    #define
    ,您需要选择Phoenix V3,因为Phoenix V2根本没有实现对lambdas的支持。默认情况下,Spirit V2出于历史/兼容性原因选择Phoenix V2。实际上,Phoenix V3更为成熟,并且修复了许多问题问题,因此我建议始终使用
    BOOST\u SPIRIT\u USE\u PHOENIX\u V3运行



[1]某些编译器的最新版本可能不需要它

,非常感谢,这确实修复了编译器错误。出于好奇,我还尝试了将每个添加项依次注释掉;但它只对未注释的两个添加项都有效。现在我好奇地想了解为什么会有效。@Anthond当然,我提到这两个添加项都是有原因的:)不过我添加了一点解释。谢谢,我刚刚注意到,如果我不将lambda包装在phoenix::bind()中,而只是将其直接传递给语义操作,那么它也可以正确编译和运行(类似于我看到的一些其他问题,其中Spirit现在处理一些具有特定签名的lambda),并删除您添加的两个
#define
。因此,您的评论是只有Phoenix V3可以处理lambdas,这使我得出结论,Spirit现在可以直接处理lambdas,但不能处理Phoenix V2,因此在Spirit和lambda之间引入Phoenix V2层是导致我错误的原因。@Anthond是的。只是,您没有介绍减少该层:Spirit默认情况下与Phoenix V2结合。即使没有
phx::bind
,您也只能隐式获得Phoenix V2。此外,请检查语义是否实际相同。如果它编译,这并不意味着它能实现您期望的功能(惰性/非惰性函数…)。但是,可能只是传递一个无状态lambda(未调用)由于隐式转换为函数指针类型而工作。
#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3