在编译时对已知N的std::元组重复
repeat to std::tuple with known N at compile time
我想在编译时解析指定数量的元素。我试过repeat()[]
指令。下面的代码显示了我的情况:
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);
编译器错误信息:
error: static assertion failed: Expecting a single element fusion sequence
static_assert(traits::has_size<Attribute, 1>::value
如果我把它写出来,它是有效的:
parse(std::begin(str), std::end(str), float_ >> ' ' >> float_ >> ' ' >> float_ ] , tup);
,但对于大量的元素,它是混乱的。
是否可以使用'repeat指令来缩短语法?
您可以在这里看到x3::repeat(3)[x3::float_]
的合成属性是一个vector<float>
,它不匹配您的属性(基本上是一个大小为3的融合序列)。请注意,合成属性不依赖于您传递的值。
为了得到你想要的,你需要另一个指令,它的类型依赖于你传递的值。然后,该指令将生成一个序列,其中它的主题被重复N次(简单地将工作"委托"给x3::sequence
将确保在属性传播方面一切正常工作)。我能想到至少两种方法:repeat<N>[parser]
或repeat(integral_constant<int,N>)[parser]
之类的东西。在下面的代码中,我选择了第二种方法,使用boost::hana::integral_constant
,它允许您使用:
custom::repeat(3_c)[ x3::float_ >> (' ' | x3::eol | x3::eoi) ]
完整代码(在WandBox上运行)
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
#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) ] );
}
相关文章:
- 专用于 std 元组的模板,而无需用户执行remove_cvref
- std::元组分配和复制/移动异常保证
- std::元组和移动语义
- std::元组作为成员替换,方便宏
- 如何从参数包构造引用的 std::元组?
- 用一个额外的元素扩展 std::array 的每个 std::元组
- std::元组大小,是不是错过了优化?
- 初始化语句中临时 std::元组的开销
- 如何改善STD ::元组在空置领域
- 就地解压缩 std::元组,而无需为 std::index_sequence 提供人工层
- 动态创建和扩展STD ::元组为参数包
- 获取std ::元组元素作为std ::变体
- std::元组到元组的映射和使用 emplace
- 检查是否所有 std::元组元素都满足条件 + 设计问题
- Q:std::元组/std::数组
- 为什么GCC警告使用STD ::元组和虚拟继承来调用非平凡的动作分配运算符
- 为什么使用std ::元组和模板派生的类扣除/替换会扣除/替换
- C++ 如何根据部分特化制作 std::元组类型?
- 由std ::元组存储的垃圾价值
- 使用 C++11 std::元组在大型项目中