我试图创建一个规则,返回通过curry Phoenix表达式构造的function<char(char const *)>
。如,
start = int_[_val = xxx];
rule<Iterator, function<char(char const *)> start;
xxx
应该是什么,以便解析字符串"5"
应该给我一个函数,它给我输入的第五个字符?我尝试过像lambda(_a = arg1)[arg1[_a]](_1)
这样的事情可能有用,但我还没有能够达到神奇的公式。
换句话说,我喜欢在解析的int的值上调用arg2[arg1]
的属性
非常感谢任何建议。请注意,我在VC2008上,所以C ++ 11 lambdas不可用。
麦克
答案 0 :(得分:2)
修正该规则声明后:
typedef boost::function<char(char const*)> Func;
qi::rule<Iterator, Func()> start;
它有效: Live On Coliru (c ++ 03)。
<强>更新强>:
为什么我最终得到这么复杂的装置?
qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1)
好。让我告诉你关于复杂功能组合与懒惰评估的快乐(在C ++模板元编程中,这些编程具有参考/值语义的惊喜):不要执行以下操作:
qi::_val = px::lambda(_a = qi::_1) [arg1[_a]] // UB!!! DON'T DO THIS
根据编译器的优化级别,这可能会 *显示。但它正在调用未定义的行为 [1] 。问题是qi::_1
将作为引用保存到qi::int_
解析器表达式公开的属性中。但是,在解析器上下文的生命周期结束后,此引用是一个悬空引用。
因此,通过无效的引用来评估函子的间接性。为避免这种情况,您应该说( Live On Coliru ):
qi::_val = px::lambda(_a = px::val(qi::_1)) [arg1[_a]]
甚至(如果你喜欢模糊的代码):
qi::_val = px::lambda(_a = +qi::_1) [arg1[_a]]
或者,您知道,您可以坚持使用绑定的嵌套lambda,因为绑定默认为qi::_1
的值语义(除非您使用phx::cref
/ { {1}}封套)。
我希望上面的分析能够让我回想起我之前在评论中提出的观点:
请注意,我不推荐这种代码风格。使用Phoenix的高阶编程非常棘手,而不是在某些嵌入式表达式模板DSL中的惰性演员中编写它们:
phx::ref
。 'Nuff说 ?
qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1)
打印
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/function.hpp>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
typedef boost::function<char(char const*)> Func;
int main()
{
typedef std::string::const_iterator Iterator;
using namespace boost::phoenix::arg_names;
qi::rule<Iterator, Func()> start;
start = qi::int_
[ qi::_val = px::bind(px::lambda[arg1[arg2]], px::lambda[arg1], qi::_1) ];
// or: [ qi::_val = px::lambda(_a = px::val(qi::_1))[arg1[_a]] ];
static char const* inputs[] = { "0", "1", "2", "3", "4", 0 };
for (char const* const* it = inputs; *it; ++it)
{
std::string const input(*it);
Iterator f(input.begin()), l(input.end());
Func function;
bool ok = qi::parse(f, l, start, function);
if (ok)
std::cout << "Parse resulted in function() -> character "
<< function("Hello") << "; "
<< function("World") << "\n";
else
std::cout << "Parse failed\n";
if (f != l)
std::cout << "Remaining unparsed: '" << std::string(f, l) << "'\n";
}
}
[1] (MSVC2013似乎崩溃了,gcc似乎可以在-O3中运行,但在-O0中也可以使用段错误。)