我正在编写模板化的 CSVParser 类,它从任何 basic_istream 对象读取数据并将其转换为给定类型的 std::tuple :
template<class Ch, class Tr, class... Types>
class CSVParser {
public:
explicit CSVParser(std::basic_istream<Ch, Tr> &istream) : istream_(istream) {
}
CSVParser& operator>>(std::tuple<Types...>& tup) {
[&] <size_t... Is> (std::index_sequence<Is...>)
{
((istream_ >> std::get<Is>(tup)), ...);
} (std::index_sequence_for<Types...>());
return *this;
}
private:
std::basic_istream<Ch, Tr>& istream_;
};
我希望可以用这种方式:
const static std::string sample_csv = "1,abc\n"
"2,def\n"
"3,ghi";
std::stringstream ss(sample_csv);
CSVParser<int, std::string> parser(ss);
std::tuple<int, std::string> data;
parser >> data;
但是,Ch 和 Tr 类型无法推导,我需要明确指定它们:
CSVParser<char, std::char_traits<char>, int, std::string> parser(ss);
在 C++20 中是否可以推导这对类型,而可变参数
class... Types
则不能?
或者我怎样才能重写我的代码来达到预期的结果?
我尝试将可变参数包移至模板参数列表的开头,但编译器认为它应该位于末尾。
无需使用
Types...
作为CSVParser
的模板参数,因为前者不包含tuple
成员。
更合适的选择是使
CSVParser
只有两个模板参数,并提供像 这样的推导指南
template<class Ch, class Tr>
class CSVParser {
public:
explicit CSVParser(std::basic_istream<Ch, Tr> &istream) : istream_(istream) {}
// ...
};
template<class Ch, class Tr>
CSVParser(std::basic_istream<Ch, Tr>&) -> CSVParser<Ch, Tr>;
这允许您从
CSVParser
对象构造 basic_istream
而无需显式指定类型
const static std::string sample_csv = /* */;
std::stringstream ss(sample_csv);
CSVParser parser(ss);
此外,
CSVParser::operator>>
可以使用 std::apply
进行简化
CSVParser& operator>>(auto& tup) {
std::apply([this](auto&... elems) {
(istream_ >> ... >> elems);
}, tup);
return *this;
}