标签:c c11 templates variadic-templates parsing
我正在开发一个简单的CSV解析器,它将文件的行存储在元组中.如果不是因为文件内的行上的条目数是变量以及它们的类型,这将是一件容易的事.因此,线条可能是这样的:
1,2.2,你好,18,世界
解析器应该能够像这样工作:
ifstream file("input.csv");
SimpleCSVParser<int, float, string, int, string> parser(file);
当我尝试实现一个解析实际行的函数时,事情就变得复杂了.在调用文件>>之前,我还没有找到从参数列表中提取下一个类型以声明变量的方法. var就可以了.我还需要在循环中执行此操作,以某种方式从每次迭代的结果构造元组.
那么如何使用普通的C 11将字符串解析为元组?
我试过这个:
template <typename ...Targs>
tuple<Targs...> SimpleCSVParser<Targs...>::iterator::operator*() {
istringstream in(cur);
in.imbue(locale(locale(), new commasep)); // for comma separation
tuple<Targs...> t;
for (size_t i = 0; i < sizeof...(Targs); ++i) {
tuple_element<i,decltype(t)>::type first;
in >> first;
auto newt = make_tuple(first);
// what do I do here?
}
}
但它不起作用,因为我用来提取类型的元组是空的.
解决方法:
看来,你试图迭代不起作用的元组索引/类型,我想.但是,你可以做的就是为每个成员调用一个读函数.我们的想法是将元组的处理委托给一个函数,该函数使用参数包将操作扩展到每个元素上的操作.的std :: index_sequence< …>可用于获取整数序列.
像这样的东西:
template <typename T>
bool read_tuple_element(std::istream& in, T& value) {
in >> value;
return true;
}
template <typename Tuple, std::size_t... I>
void read_tuple_elements(std::istream& in, Tuple& value, std::index_sequence<I...>) {
std::initializer_list<bool>{ read_tuple_element(in, std::get<I>(value))... });
}
template <typename ...Targs>
tuple<Targs...> SimpleCSVParser<Targs...>::iterator::operator*() {
std::istringstream in(cur);
in.imbue(std::locale(std::locale(), new commasep)); // for comma separation
std::tuple<Targs...> t;
read_tuple_elements(in, t, std::make_index_sequence<sizeof...(Targs)>{});
if (in) { // you may want to check if all data was consumed by adding && in.eof()
// now do something with the filled t;
}
else {
// the value could *not* successfully be read: somehow deal with that
}
}
上面代码的基本思想就是创建一个合适的read_tuple_element()调用序列.在跳转到通用代码之前,假设我们想要实现std :: tuple< T0,T1,T2>的读取.价值只有三个要素.我们可以使用(使用rte()而不是read_tuple_element()来实现读取)
rte(get<0>(value)), rte(get<1>(value)), rte(get<2>(value));
现在,不是为每个元素编写这个,如果我们有一个索引序列std :: size_t …我可以使用这个序列[几乎]使用
rte(get<I>(value))...;
但是,不允许像这样扩展参数包.相反,参数包需要放在某个上下文中.上面的代码使用了std :: initializer_list< bool>为此目的:std :: initializer_list< T>的元素.按列出的顺序构建.也就是说,我们得到了
std::initializer_list<bool>{ rte(get<I>(value))... };
缺少的是如何创建参数包我评估一系列合适的索引.方便地,标准库定义std :: make_index_sequence< Size>这会创建一个std :: index_sequence< I ...> I的值为0,1,2,…,Size-1的序列.因此,使用std :: make_index_sequence< sizeof ...(Targs){}调用read_tuple_elements()会创建一个具有合适的参数列表的对象,这些参数可以推导出来,然后用于将元组扩展为传递给read_tuple_element的元素序列( ).
标签:c,c11,templates,variadic-templates,parsing 来源: https://codeday.me/bug/20190829/1761389.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。