我无法弄清楚我的代码有什么问题。 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,end,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,end,expr))
{
std::cout << "[+] Parsed!\n";
}
else
{
std::cout << "[-] Parsing failed.\n";
}
return 0;
}
感谢您的提示,hkaiser。
答案 0 :(得分:7)
几条评论:a)不要使用随Boost V1.39和V1.40一起发布的Spirit V2 beta版。至少使用Spirit V2.1(与Boost V1.41一起发布),因为它包含 lot 的错误修复和性能增强(编译时和运行时性能)。如果您无法切换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, end,
+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。