C++ Boost.Spirit.Qi使用中的错误雪崩

C++ Boost.Spirit.Qi使用中的错误雪崩,c++,c++11,boost-spirit,boost-spirit-qi,C++,C++11,Boost Spirit,Boost Spirit Qi,我无法找出我的代码出了什么问题。Boost的模板让我发疯了!我无法理解这一切,所以我不得不问 这个怎么了 #include <iostream> #include <boost/lambda/lambda.hpp> #include <boost/spirit/include/qi.hpp> void parsePathTest(const std::string &path) { namespace lambda = boost::lamb

我无法找出我的代码出了什么问题。Boost的模板让我发疯了!我无法理解这一切,所以我不得不问

这个怎么了

#include <iostream>
#include <boost/lambda/lambda.hpp>
#include <boost/spirit/include/qi.hpp>

void parsePathTest(const std::string &path)
{
    namespace lambda = boost::lambda;
    using namespace boost::spirit;

    const std::string permitted = "._\\-#@a-zA-Z0-9";
    const std::string physicalPermitted = permitted + "/\\\\";
    const std::string archivedPermitted = permitted + ":{}";

    std::string physical,archived;

    // avoids non-const reference to rvalue
    std::string::const_iterator begin = path.begin(),end = path.end();

    // splits a string like "some/nice-path/while_checking:permitted#symbols.bin"
    // as physical = "some/nice-path/while_checking"
    // and archived = "permitted#symbols.bin" (if this portion exists)
    // I could barely find out the type for this expression
    auto expr
        =   ( +char_(physicalPermitted) ) [lambda::var(physical) = lambda::_1]
            >> -(
                    ':'
                    >> (
                           +char_(archivedPermitted) [lambda::var(archived) = lambda::_1]
                       )
                )
        ;

    // the error occurs in a template instantiated from here
    qi::parse(begin,end,expr);

    std::cout << physical << '\n' << archived << '\n';
}
--编辑2

我仍然不知道为什么它在我的旧版本Boost(1.39)中不起作用,但是升级到boost1.42解决了这个问题。以下代码可以在Boost 1.42中完美编译和运行:

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

int main()
{
    using namespace boost::spirit;

    std::string str = "sample";
    std::string::const_iterator begin(str.begin()), end(str.end());

    auto expr
        =   ( +qi::char_("a-zA-Z") ) // notice this line; char_ is not part of 
                                     // boost::spirit anymore (or maybe I didn't 
                                     // include the right headers, but, regardless, 
                                     // khaiser said I should use qi::char_, so here 
                                     // it goes)
        ;

    // the error occurs in a template instantiated from here
    if (qi::parse(begin,end,expr))
    {
        std::cout << "[+] Parsed!\n";
    }
    else
    {
        std::cout << "[-] Parsing failed.\n";
    }

    return 0;
}
#包括
#包括
int main()
{
使用名称空间boost::spirit;
std::string str=“sample”;
std::string::const_迭代器begin(str.begin()),end(str.end());
自动导出
=(+qi::char_uuz(“a-zA-Z”)//注意这一行;char_uuu不是
//精神再也没有了(也许我没有了)
//包括正确的标题,但无论如何,
//khaiser说我应该使用qi::char_,所以这里
//就这样)
;
//错误发生在从此处实例化的模板中
if(qi::parse(begin、end、expr))
{
std::cout几句话:a)不要使用随Boost V1.39和V1.40一起发布的Spirit V2 beta版。至少使用Spirit V2.1(与Boost V1.41一起发布),因为它包含大量错误修复和性能增强(编译时和运行时性能)。如果您无法切换Boost版本,请阅读以了解如何继续。b)尽量避免使用Boost::lambda或Boost::bind with Spirit V2.x。是的,我知道,文档说它可以工作,但您必须知道自己在做什么。请改用Boost::phoenix表达式。Spirit“了解”phoenix,这使得编写语义操作更容易。如果您使用phoenix,您的代码如下所示:

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

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

std::string physical, archived;  
auto expr 
    =   ( +char_(physicalPermitted) ) [phoenix::ref(physical) = qi::_1] 
    >> -( 
            ':' 
            >> ( +char_(archivedPermitted) )[phoenix::ref(archived) = qi::_1] 
        ) 
    ; 
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间phoenix=boost::phoenix;
std::字符串物理,存档;
自动导出
=(+char_(物理允许))[phoenix::ref(物理)=qi::_1]
>> -( 
':' 
>>(+char_(archivedPermited))[phoenix::ref(archived)=qi::_1]
) 
; 
但如果使用Spirit的内置属性传播规则,您的整个解析器将变得更加简单:

std::string physical;
boost::optional<std::string> archived;  

qi::parse(begin, end, 
    +qi::char_(physicalPermitted) >> -(':' >> +qi::char_(archivedPermitted)),
    physical, archived);
std::字符串物理;
boost::可选存档;
解析(开始,结束,
+qi::char_uU2;(物理允许)>>-(':'>>+qi::char_U2;(物理允许)),
物理的,归档的);
i、 完全不需要语义动作。如果您需要更多关于属性处理的信息,请参阅Spirit网站上关于属性魔力的系列文章

编辑:

关于静态_断言问题:是的,静态_断言可以改善错误消息,因为它可以用于尽早触发编译器错误。事实上,Spirit已经广泛使用了这种技术。但不可能在所有情况下都保护用户不收到这些巨大的错误消息,但仅针对那些用户错误,程序会MMER确实期望。只有概念(不幸的是没有把它纳入新的C++标准)可能被用来一般减少错误消息的大小。 关于Boost的字符串算法问题:当然可以将此库用于您的简单任务。使用Boost.Tokenizer可能会更好(如果您只需要在“:”处拆分输入字符串)。Spirit的性能应与字符串算法的相应性能相当,但这当然取决于您将编写的代码。如果您假设所使用的字符串算法将需要对输入字符串数据进行一次传递,则Spirit不会更快(因为它也进行了一次传递)


Boost字符串算法和Boost标记器都无法验证匹配的字符。您的Spirit语法只匹配您在字符类中指定的字符。因此,如果您需要此匹配/验证,您应该使用Spirit或Boost正则表达式。

出现前几个错误仍然会有所帮助。另外,更喜欢使用已有的库。它们附带免费的bug修复,并且已经过测试。GMan:你认为boost库是由n2liquid自行开发的吗?也许你应该自己看看boost.org!@Pontus:什么?也许我有点误解,但我不知道你是怎么从我的评论中得到的。我很清楚“我不知道上面引用的实现是不是一个好主意,或者我是否应该使用Boost的字符串算法库。”也许我不明白,但据我所知,你是在问是否要使用Bosot.String库还是你自己亲手制作的东西。这不对吗?啊,我稍后会尝试更新我的Boost副本。它已经在我的备份分区中重新安装了至少3次,为了方便起见,我一直在使用。我决定使用Boost String Algori但是,正如我“看到”的,这个实现的THM做得更好。Spirit对我来说似乎还是太过分了,我发布了这篇文章,想知道为什么它在我有朝一日需要它的情况下不起作用。但问题真的不是动作,而是操作符。我试过Kleene Star和Plus操作符,但都有类似的错误。好吧,我想你的问题之一是错误的p围绕第二个+字符的主题(请参阅上面的示例以了解正确的代码)。这实际上应该会使您的代码编译,至少它应该会将您看到的模板错误中的一大块分割开来。我已经更新了我的第一篇帖子。即使是最小的代码也会导致大量错误。您添加到问题中的代码使用Spirit V2.2(来自Boost 1.42)编译得很好.嗯,它几乎可以编译,您需要将char_uu限定为qi::char_uu。正如我所说的,取自Boost 1.41的Spirit也同样适用,但请不要使用旧版本。我已经尝试过Bo
std::string physical;
boost::optional<std::string> archived;  

qi::parse(begin, end, 
    +qi::char_(physicalPermitted) >> -(':' >> +qi::char_(archivedPermitted)),
    physical, archived);