如何通过构造函数注入std::basic_istream而不显式指定<CharT,Traits>

问题描述 投票:0回答:1

我正在编写模板化的 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
则不能? 或者我怎样才能重写我的代码来达到预期的结果?

我尝试将可变参数包移至模板参数列表的开头,但编译器认为它应该位于末尾。

templates c++20 iostream stdtuple type-deduction
1个回答
0
投票

无需使用

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;
}

演示

© www.soinside.com 2019 - 2024. All rights reserved.