gpt4 book ai didi

c++ - 使用右值引用重载模板化可变参数运算符

转载 作者:搜寻专家 更新时间:2023-10-31 02:06:44 24 4
gpt4 key购买 nike

这是我的定义:

template<typename ... TL>
struct TemplatedType { };

template<typename ... TL>
std::istream& operator>>(std::istream& is, TemplatedType<TL ...> & sp)
{
// do stuff

return is;
}

和用法:

std::istringstream iss("I'd like some pancakes, please");
TemplatedType<int> a;
iss >> a;

它工作得很好,但是我想接收模板化参数作为右值引用:

template<typename ... TL>
std::istream& operator>>(std::istream& is, const TemplatedType<TL && ...> & sp) {...}

然后,编译器开始大喊:

C2678 binary '>>': no operator found which takes a left-hand operand of type 'std::istringstream' (or there is no acceptable conversion)

问题出在哪里?


动机:我想制作一个可以以这种方式使用的 split 函数:

std::istringstream iss("alpha:=10/50.1");

std::string x;
int y;
double z;

iss >> split(x, ':', '=', y, '/', z); // sets x=alpha, y=10, z=50.1

因此该函数需要能够接收左值和右值引用。

最佳答案

有趣的问题。

Jarod42 解释了问题出在哪里:如果你定义一个 TemplatedType<int> a; , 这可以匹配

template<typename ... TL>
std::istream& operator>>(std::istream& is,
const TemplatedType<TL ...> & sp)

但无法匹配

template<typename ... TL>
std::istream& operator>>(std::istream& is,
const TemplatedType<TL & ...> & sp)

因为你有一个 int并且需要 int& .

但是如何开始工作

iss >> split(x, ':', '=', y, '/', z); 

?

嗯...我想你可以放一个std::tuple里面TemplatedType

template <typename ... TL>
struct TemplatedType
{ std::tuple<TL...> t; };

所以 split() (我已将其重命名为 mySplit() )简单地变成了

template <typename ... TL>
TemplatedType<TL...> mySplit (TL && ... al)
{ return { std::forward_as_tuple(al...) }; }

mySplit(x, ':', '=', y, '/', z);

哪里xstd::string , yintzdouble , 你获得一个 TemplatedType<std::string &, char, char, int &, char, double &> .

你可以写一个operator<<()调用第一个辅助函数

template <typename ... TL>
std::istream & operator>> (std::istream & is,
TemplatedType<TL...> const & sp)
{
myHelper1(is, sp, std::index_sequence_for<TL...>{});

return is;
}

第一个辅助函数提取元组中包含的元素 sp并调用第二个辅助函数

template <typename ... TL, std::size_t ... IL>
void myHelper1 (std::istream & is,
TemplatedType<TL...> const & sp,
std::index_sequence<IL...> const &)
{ myHelper2(is, std::get<IL>(sp.t)...); }

第二个辅助函数稍微复杂一些。

这是一组递归函数,每次调用都会消耗一个/两个元素。

首先是接地(端子)情况

void myHelper2 (std::istream &)
{ }

然后特std::string具有以下常量的情况 char , 分隔符(没有分隔符,如果你简单地写 is >> s ,你会得到包含在 is 中的完整字符串)

template <typename ... TS>
void myHelper2 (std::istream & is, std::string & s, char const & delim,
TS && ... ts)
{
std::getline(is, s, delim);

myHelper2(is, std::forward<TS>(ts)...);
}

接下来接收常量 char 的版本(在您的示例中为 :=/;但第一个用作字符串的分隔符)并丢弃 char来自 is (并且,如果需要,检查丢弃的字符是否是相同的参数字符)

template <typename ... TS>
void myHelper2 (std::istream & is, char const ch, TS && ... ts)
{
char ch2;

is >> ch2;

// check if `ch` == `ch2`? exception otherwise?

myHelper2(is, std::forward<TS>(ts)...);
}

最后一个一般情况,接收通用(类型 T)引用

template <typename T, typename ... TS>
void myHelper2 (std::istream & is, T & t, TS && ... ts)
{
is >> t;

myHelper2(is, std::forward<TS>(ts)...);
}

下面是一个完整的例子。

从 C++14 开始工作,因为 std::index_sequencestd::index_sequence_for在 C++14 中引入。但是如果你想要一个 C++11 解决方案,为他们写一个替代品很简单

#include <tuple>
#include <sstream>
#include <iostream>

template <typename ... TL>
struct TemplatedType
{ std::tuple<TL...> t; };

void myHelper2 (std::istream &)
{ }

template <typename ... TS>
void myHelper2 (std::istream &, char const, TS && ...);

template <typename T, typename ... TS>
void myHelper2 (std::istream &, T &, TS && ...);

template <typename ... TS>
void myHelper2 (std::istream & is, std::string & s, char const & delim,
TS && ... ts)
{
std::getline(is, s, delim);

myHelper2(is, std::forward<TS>(ts)...);
}

template <typename ... TS>
void myHelper2 (std::istream & is, char const ch, TS && ... ts)
{
char ch2;

is >> ch2;

// check if `ch` == `ch2`? exception otherwise?

myHelper2(is, std::forward<TS>(ts)...);
}

template <typename T, typename ... TS>
void myHelper2 (std::istream & is, T & t, TS && ... ts)
{
is >> t;

myHelper2(is, std::forward<TS>(ts)...);
}

template <typename ... TL, std::size_t ... IL>
void myHelper1 (std::istream & is,
TemplatedType<TL...> const & sp,
std::index_sequence<IL...> const &)
{ myHelper2(is, std::get<IL>(sp.t)...); }

template <typename ... TL>
std::istream & operator>> (std::istream & is,
TemplatedType<TL...> const & sp)
{
myHelper1(is, sp, std::index_sequence_for<TL...>{});

return is;
}


template <typename ... TL>
TemplatedType<TL...> mySplit (TL && ... al)
{ return { std::forward_as_tuple(al...) }; }

int main ()
{
std::istringstream iss("alpha:=10/50.1");

std::string x;
int y{};
double z{};

iss >> mySplit(x, ':', '=', y, '/', z);

std::cout << "- x: " << x << std::endl; // print alpha
std::cout << "- y: " << y << std::endl; // print 10
std::cout << "- z: " << z << std::endl; // print 50.1
}

关于c++ - 使用右值引用重载模板化可变参数运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49814797/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com