[英]repeat to std::tuple with known N at compile time
i want to parse a at compile time specified number of elements. 我想在编译时解析指定数量的元素。 I've tried the
repeat()[]
directive. 我已经尝试了
repeat()[]
指令。 The following code shows my case: 以下代码显示了我的情况:
using namespace x3;
std::tuple<float, float, float> tup;
std::string str{"0.3 0.2 0.1"};
auto ret = parse(std::begin(str), std::end(str), repeat(3)[ float_ >> (' ' | eol) ] , tup);
The compiler error message: 编译器错误消息:
error: static assertion failed: Expecting a single element fusion sequence
static_assert(traits::has_size<Attribute, 1>::value
It works if i would write it out: 如果我写出来的话它会工作:
parse(std::begin(str), std::end(str), float_ >> ' ' >> float_ >> ' ' >> float_ ] , tup);
but with a large number of elements it is confusion. 但是由于存在大量元素,这是一种混乱。
Is there a way to shorten the grammar with a ' repeat ' directive ? 有没有办法用' 重复 '指令缩短语法?
As you can see here the synthesized attribute of x3::repeat(3)[x3::float_]
is a vector<float>
and that does not match your attribute (basically a fusion sequence of size 3). 正如您在这里看到的,
x3::repeat(3)[x3::float_]
的合成属性是一个vector<float>
,它与您的属性(基本上是大小为3的融合序列)不匹配。 Note that the synthesized attribute does not depend on the value you pass. 请注意,合成属性不依赖于您传递的值。
In order to get what you want you'll need another directive, one which type does depend on the value you pass. 为了获得你想要的东西,你需要另一个指令,一个类型取决于你传递的值。 This directive would then generate a sequence where it's subject is repeated N times (simply "delegating" the work to
x3::sequence
would make sure that everything works correctly in regards to attribute propagation). 然后,该指令将生成一个序列,其中主题被重复N次(简单地将工作“委托”到
x3::sequence
将确保一切在属性传播方面正常工作)。 I can think of at least two ways this could work: something like repeat<N>[parser]
or something like repeat(integral_constant<int,N>)[parser]
. 我可以想到至少有两种方法可以解决这个问题:
repeat<N>[parser]
或像repeat(integral_constant<int,N>)[parser]
。 In the code below I have chosen the second approach using boost::hana::integral_constant
, which allows you to use: 在下面的代码中,我选择了使用
boost::hana::integral_constant
的第二种方法,它允许您使用:
custom::repeat(3_c)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ]
Full Code (Running on WandBox) 完整代码 (在WandBox上运行)
custom_repeat.hpp custom_repeat.hpp
#include <type_traits>
#include <boost/spirit/home/x3.hpp>
namespace custom
{
struct repeat_gen
{
template <int Size>
struct repeat_gen_lvl1
{
//using overloads with integral constants to avoid needing to partially specialize a function
//this actually builds the sequence of parsers
template <typename Parser,int N>
auto generate_sequence(Parser const& parser, std::integral_constant<int,N>) const
{
return generate_sequence(parser,std::integral_constant<int,N-1>{}) >> parser;
}
template <typename Parser>
auto generate_sequence(Parser const parser,std::integral_constant<int,1>) const
{
return parser;
}
template<typename Subject>
auto operator[](Subject const& subject) const
{
//here the actual sequence is generated
return generate_sequence(boost::spirit::x3::as_parser(subject), std::integral_constant<int,Size>{});
}
};
template <typename IntConstant>
repeat_gen_lvl1<int(IntConstant::value)>
operator()(IntConstant) const
{
//returns an object that know the size of the wanted sequence and has an operator[] that will capture the subject
return {};
}
template <typename IntegerType, typename Enable=std::enable_if_t<std::is_integral<IntegerType>::value> >
auto operator()(IntegerType n) const
{
return boost::spirit::x3::repeat(n);
}
};
//this object's only purpose is having an operator()
auto const repeat = repeat_gen{};
}
main.cpp main.cpp中
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/std_tuple.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/hana/integral_constant.hpp>
#include <boost/mpl/int.hpp>
#include "custom_repeat.hpp"
namespace x3 = boost::spirit::x3;
using namespace boost::hana::literals;
template <typename T>
void print_attr(const std::vector<T>& vec)
{
std::cout << "Vector: ";
for(const auto& elem : vec)
std::cout << "[" << elem << "]";
}
template <typename Sequence, typename Enable=std::enable_if_t<boost::fusion::traits::is_sequence<Sequence>::value> >
void print_attr(const Sequence& seq)
{
std::cout << "Sequence: " << boost::fusion::as_vector(seq);
}
template <typename Attr,typename Parser>
void parse(const std::string& str, const Parser& parser)
{
Attr attr;
std::string::const_iterator iter = std::begin(str), end = std::end(str);
bool ret = x3::parse(iter, end, parser, attr);
if(ret && (iter==end))
{
std::cout << "Success.\n";
print_attr(attr);
std::cout << std::endl;
}
else
{
std::cout << "Something failed. Unparsed: ->|" << std::string(iter,end) << "|<-" << std::endl;
}
}
struct float_holder
{
float val;
};
BOOST_FUSION_ADAPT_STRUCT(float_holder,val);
int main()
{
boost::mpl::int_<2> two;
std::integral_constant<int,1> one;
parse<std::tuple<float,float,float> >("0.3 0.2 0.1", custom::repeat(3_c)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ] );
parse<std::pair<float,float> >("0.2 0.1", custom::repeat(two)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ] );
parse<float_holder>("0.1", custom::repeat(one)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ] );
parse<std::vector<float> >("0.3 0.2 0.1", custom::repeat(3)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ] );
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.