Boost Spirit X3不能用可变因子编译重复指令 [英] Boost Spirit X3 cannot compile repeat directive with variable factor
问题描述
我尝试使用Boost Spirit X3指令重复并使用可变的重复因子。基本思想是头部+有效载荷,其中头部指定有效载荷的大小。一个简单的例子3 1 2 3被解释为header = 3,data = {1,2,3}(3个整数)。
I am trying to use the Boost Spirit X3 directive repeat with a repetition factor that is variable. The basic idea is that of a header + payload, where the header specifies the size of the payload. A simple example "3 1 2 3" is interpreted as header = 3, data= {1, 2, 3} (3 integers).
从精灵文档。它使用boost phoenix引用包装可变因子: http://www.boost.org/doc/libs/1_50_0/libs/spirit/doc/html/spirit/qi/reference/directive/repeat.html
I could only find examples from the spirit qi documentation. It uses boost phoenix reference to wrap the variable factor: http://www.boost.org/doc/libs/1_50_0/libs/spirit/doc/html/spirit/qi/reference/directive/repeat.html
std::string str;
int n;
test_parser_attr("\x0bHello World",
char_[phx::ref(n) = _1] >> repeat(phx::ref(n))[char_], str);
std::cout << n << ',' << str << std::endl; // will print "11,Hello World"
:
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <iostream>
namespace x3 = boost::spirit::x3;
using x3::uint_;
using x3::int_;
using x3::phrase_parse;
using x3::repeat;
using x3::space;
using std::string;
using std::cout;
using std::endl;
int main( int argc, char **argv )
{
string data("3 1 2 3");
string::iterator begin = data.begin();
string::iterator end = data.end();
unsigned int n = 0;
auto f = [&n]( auto &ctx ) { n = x3::_attr(ctx); };
bool r = phrase_parse( begin, end, uint_[f] >> repeat(boost::phoenix::ref(n))[int_], space );
if ( r && begin == end )
cout << "Parse success!" << endl;
else
cout << "Parse failed, remaining: " << string(begin,end) << endl;
return 0;
}
使用boost 1.59.0和clang ++编译上面的代码(flags:-std = c ++ 14)给出以下结果:
Compiling the code above with boost 1.59.0 and clang++ (flags: -std=c++14) gives the following:
boost_1_59_0/boost/spirit/home/x3/directive/repeat.hpp:72:47: error: no matching constructor for
initialization of 'proto_child0' (aka 'boost::reference_wrapper<unsigned int>')
typename RepeatCountLimit::type i{};
如果我硬编码 repeat(3)
repeat(boost :: phoenix :: ref(n))
它可以正常工作,但它不是一个可能的解决方案,因为它应该支持一个可变的重复因子。
If I hardcode repeat(3)
instead of repeat(boost::phoenix::ref(n))
it works properly, but it is not a possible solution since it should support a variable repetition factor.
使用 repeat(n)
的编译成功完成,但无法使用以下输出解析:
解析失败,剩余:1 2 3
Compilation with repeat(n)
completes successfully, but it fails parsing with the following output:
"Parse failed, remaining: 1 2 3"
查看 boost / spirit / home / x3 / directive / repeat.hpp:72
它调用模板类型的空构造函数 RepeatCountLimit :: type
variable i
然后在for循环中分配,遍历min和max。然而由于类型是一个引用,它应该在构造函数中初始化,因此编译失败。代码从以前的库版本boost / spirit / home / qi / directive / repeat.hpp:162它是直接分配:
Looking at the source code for boost/spirit/home/x3/directive/repeat.hpp:72
it calls the empty constructor for template type RepeatCountLimit::type
variable i
and then assign during the for loop, iterating over min and max. However since the type is a reference it should be initialized in the constructor, so compilation fails. Looking at the equivalent source code from the previous library version boost/spirit/home/qi/directive/repeat.hpp:162 it is assigned directly:
typename LoopIter::type i = iter.start();
我不知道我在做什么在这里,或者如果x3目前不支持变量重复因子,我将感谢一些帮助解决这个问题。
I am not sure what I am doing wrong here, or if x3 currently does not support variable repetition factors. I would appreciate some help solving this issue. Thank you.
推荐答案
根据我收集,阅读源和邮件列表,Phoenix没有集成到X3中:原因是c ++ 14使大部分过时。
From what I gather, reading the source and the mailing list, Phoenix is not integrated into X3 at all: the reason being that c++14 makes most of it obsolete.
我同意这留下了一些地方,Qi曾经有优雅的解决方案,例如 eps(DEFERRED_CONDITION)
, lazy(* RULE_PTR)
( Nabialek招),而且确实是这种情况。
I agree that this leaves a few spots where Qi used to have elegant solutions, e.g. eps(DEFERRED_CONDITION)
, lazy(*RULE_PTR)
(the Nabialek trick), and indeed, this case.
Spirit X3仍在开发中,所以我们可能会看到这个添加的
Spirit X3 is still in development, so we might see this added¹
现在,Spirit X3有一个概括性的语境环境。这基本上替换了 locals<>
,在某些情况下是继承的参数,并且可以/用于/验证此特定情况下的元素数量:
For now, Spirit X3 has one generalized facility for stateful context. This essentially replaces locals<>
, in some cases inherited arguments, and can be /made to/ validate the number of elements in this particular case as well:
-
x3 :: with
²
x3::with
²
以下是使用方法:
with<_n>(std::ref(n))
[ omit[uint_[number] ] >>
*(eps [more] >> int_) >> eps [done] ]
这里, _n
是标识用于检索 get< _n>(cxtx)
的上下文元素的标签类型。
Here, _n
is a tag type that identifies the context element for retrieval with get<_n>(cxtx)
.
请注意,目前我们必须使用引用封装到小值
n
,因为与< _n>(0u)
将导致上下文中的常量元素。我假设这也是一个QoI,可以解除为X#成熟
Note, currently we have to use a reference-wrapper to an lvalue
n
becausewith<_n>(0u)
would result in constant element inside the context. I suppose this, too, is a QoI that may be lifted as X# matures
现在,对于语义动作:
unsigned n;
struct _n{};
auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };
这将解析的无符号数存储到上下文中。 (其实,由于 ref(n)
绑定,它实际上不是上下文的一部分,如上所述)
This stores the parsed unsigned number into the context. (In fact, due to the ref(n)
binding it's not actually part of the context for now, as mentioned)
auto more = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) > _val(ctx).size(); };
这里我们检查我们实际上不是full
Here we check that we're actually not "full" - i.e. more integers are allowed
auto done = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };
这里我们检查我们是否完整
Here we check that we're "full" - i.e. no more integers are allowed.
kbd> Live On Coliru
#include <string>
#include <iostream>
#include <iomanip>
#include <boost/spirit/home/x3.hpp>
int main() {
for (std::string const input : {
"3 1 2 3", // correct
"4 1 2 3", // too few
"2 1 2 3", // too many
//
" 3 1 2 3 ",
})
{
std::cout << "\nParsing " << std::left << std::setw(20) << ("'" + input + "':");
std::vector<int> v;
bool ok;
{
using namespace boost::spirit::x3;
unsigned n;
struct _n{};
auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };
auto more = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) > _val(ctx).size(); };
auto done = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };
auto r = rule<struct _r, std::vector<int> > {}
%= with<_n>(std::ref(n))
[ omit[uint_[number] ] >> *(eps [more] >> int_) >> eps [done] ];
ok = phrase_parse(input.begin(), input.end(), r >> eoi, space, v);
}
if (ok) {
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout << v.size() << " elements: ", " "));
} else {
std::cout << "Parse failed";
}
}
}
>
Which prints:
Parsing '3 1 2 3': 3 elements: 1 2 3
Parsing '4 1 2 3': Parse failed
Parsing '2 1 2 3': Parse failed
Parsing ' 3 1 2 3 ': 3 elements: 1 2 3
¹在[精神]邮寄名单上支持/发表意见)
¹ lend your support/voice at the [spirit-general] mailing list :)
²找不到合适的文档链接,但在某些示例中使用
² can't find a suitable documentation link, but it's used in some of the samples
这篇关于Boost Spirit X3不能用可变因子编译重复指令的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!