加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – Boost.Spirit.Qi用法中的错误雪崩

发布时间:2020-12-16 09:26:15 所属栏目:百科 来源:网络整理
导读:我无法弄清楚我的代码有什么问题. Boost的模板让我变得疯狂!我不能在这一切中做出正面或反面,所以我不得不问. 这有什么问题? #include iostream#include boost/lambda/lambda.hpp#include boost/spirit/include/qi.hppvoid parsePathTest(const std::strin
我无法弄清楚我的代码有什么问题. 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';
}

错误的数量是巨大的;我会建议那些想要帮助他们进行编译的人(相信我,在这里粘贴是不切实际的).我使用的是最新的TDM-GCC版本(GCC 4.4.1)和Boost版本1.39.00.

作为奖励,我想问另外两件事:C 0x的新static_assert功能是否会在这个意义上帮助Boost,以及我上面引用的实现是否是一个好主意,或者我是否应该使用Boost的字符串算法库.后者可能会提供更好的表现吗?

谢谢.

– 编辑

以下非常小的示例首先失败,其错误与上面的代码完全相同.

#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
        =   ( +char_("a-zA-Z") )
        ;

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

    return 0;
}

– 编辑2

我仍然不知道为什么它在我的旧版Boost(1.39)中不起作用,但升级到Boost 1.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,expr))
    {
        std::cout << "[+] Parsed!n";
    }
    else
    {
        std::cout << "[-] Parsing failed.n";
    }

    return 0;
}

感谢您的提示,hkaiser.

解决方法

几点评论:a)不要使用随Boost V1.39和V1.40一起发布的Spirit V2 beta版本.至少使用Spirit V2.1(与Boost V1.41一起发布),因为它包含许多错误修复和性能增强(编译时和运行时性能).如果无法切换Boost版本,请阅读 here以了解如何继续操作. b)尽量避免在Spirit V2.x中使用boost :: lambda或boost :: bind.是的,我知道,文档说它有效,但你必须知道你在做什么.请改用boost :: 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] 
        ) 
    ;

但是如果您使用Spirit的内置属性传播规则,您的整体解析器将变得更简单:

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

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

即根本不需要语义动作.如果您需要有关属性处理的更多信息,请参阅Spirit网站上有关属性魔法的文章系列.

编辑:

关于static_assert问题:yes static_assert,可以改进错误消息,因为它可以尽早用于触发编译器错误.事实上,Spirit已经广泛使用这种技术.但是不可能保护用户在所有情况下都不会收到那些巨大的错误消息,而只是针对程序员所期望的那些用户错误.只有概念(不幸的是,它没有进入新的C标准)可能被用来通常减少错误消息的大小.

关于你的Boost的字符串算法问题:当然,你可以将这个库用于简单的任务.您甚至可以更好地使用Boost.Tokenizer(如果您只需要将输入字符串拆分为’:’). Spirit的性能应该与字符串算法的相应性能相当,但这肯定取决于您要编写的代码.如果你假设使用的字符串算法需要对输入字符串数据进行一次传递,那么Spirit将不会更快(因为它也会执行一次传递).

Boost字符串算法和Boost Tokenizer都不能为您提供匹配字符的验证.您的Spirit语法仅匹配您在角色类中指定的字符.因此,如果您需要此匹配/验证,则应使用Spirit或Boost Regex.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读