如何使用转发将右值转换为左值引用?
How to use forwarding to cast rvalue to lvalue reference?
当我不关心返回的 int 数据时,我正在尝试使用重载函数来隐藏将 int 引用传递给实用程序函数。为什么我需要使用 T&
而不是 T
作为模板参数?为什么我需要将 i
定义为右值的中间函数?
class DataClass
{
};
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
// I would like to remove this function
template <typename T>
bool func(T& data, int&& i) {
return func(std::forward<T&>(data), std::forward<int&>(i));
}
template <typename T>
bool func(T& data) {
// Why doesn't this line work?
// return func(std::forward<T>(data), std::forward<int>(0));
return func(std::forward<T&>(data), 0);
}
int main(int argc, char ** argv)
{
DataClass d;
func<DataClass>(d);
return 0;
}
这里根本不需要 std::forward
。除了第二次重载中的 int&& i
外,您的参数都声明为 non-const 左值引用,因此您不能将右值传递给它们中的任何一个。而在int&&
重载中,如果你想从右值函数中调用左值函数,你只需将参数命名为i
,因为名称总是一个左值
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
template <typename T>
bool func(T& data, int&& i) {
return func(data, i);
}
template <typename T>
bool func(T& data) {
return func(data, 0);
}
如果您想删除一个函数,请注意它实际上是 int&
做了一些有效的不同的事情:它将 i
更改为 1。从技术上讲,右值重载也可以,但有些东西已经作为右值传递的那一点之后通常应该被忽略,因此调用者应该只指望 func(T&, int&&)
将消息打印到 cout
。并取一个 int
不是左值...只需取一个 int
.
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
template <typename T>
bool func(T& data, int i=0) {
return func(data, i); // effect on i is ignored.
}
// Okay to pass a const int?
template <typename T>
bool func(T&, const volatile int&&) = delete;
第三个删除的模板保留了原始代码的一种行为,但不清楚您是否真的想要这种行为。在函数中
void test() {
DataClass d;
const int n = 5;
func(d, n);
}
...原始代码将无法编译,因为 const int
左值不能绑定到 int&
或 int&&
。但是,通过将 n
的副本作为普通 int
参数,对简单 int
参数的更改将允许此 test
进行编译。然后对 int i
的更改将被丢弃,即使您将 n
赋给了函数。删除的模板更匹配 const int
左值 n
,因此它会导致 test
无法编译。如果您确实想要 func(d, n)
有效但对 n
没有影响的行为,只需取出已删除的模板即可。
当我不关心返回的 int 数据时,我正在尝试使用重载函数来隐藏将 int 引用传递给实用程序函数。为什么我需要使用 T&
而不是 T
作为模板参数?为什么我需要将 i
定义为右值的中间函数?
class DataClass
{
};
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
// I would like to remove this function
template <typename T>
bool func(T& data, int&& i) {
return func(std::forward<T&>(data), std::forward<int&>(i));
}
template <typename T>
bool func(T& data) {
// Why doesn't this line work?
// return func(std::forward<T>(data), std::forward<int>(0));
return func(std::forward<T&>(data), 0);
}
int main(int argc, char ** argv)
{
DataClass d;
func<DataClass>(d);
return 0;
}
这里根本不需要 std::forward
。除了第二次重载中的 int&& i
外,您的参数都声明为 non-const 左值引用,因此您不能将右值传递给它们中的任何一个。而在int&&
重载中,如果你想从右值函数中调用左值函数,你只需将参数命名为i
,因为名称总是一个左值
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
template <typename T>
bool func(T& data, int&& i) {
return func(data, i);
}
template <typename T>
bool func(T& data) {
return func(data, 0);
}
如果您想删除一个函数,请注意它实际上是 int&
做了一些有效的不同的事情:它将 i
更改为 1。从技术上讲,右值重载也可以,但有些东西已经作为右值传递的那一点之后通常应该被忽略,因此调用者应该只指望 func(T&, int&&)
将消息打印到 cout
。并取一个 int
不是左值...只需取一个 int
.
template <typename T>
bool func(T& data, int& i) {
i = 1;
cout << "it worked!" << endl;
}
template <typename T>
bool func(T& data, int i=0) {
return func(data, i); // effect on i is ignored.
}
// Okay to pass a const int?
template <typename T>
bool func(T&, const volatile int&&) = delete;
第三个删除的模板保留了原始代码的一种行为,但不清楚您是否真的想要这种行为。在函数中
void test() {
DataClass d;
const int n = 5;
func(d, n);
}
...原始代码将无法编译,因为 const int
左值不能绑定到 int&
或 int&&
。但是,通过将 n
的副本作为普通 int
参数,对简单 int
参数的更改将允许此 test
进行编译。然后对 int i
的更改将被丢弃,即使您将 n
赋给了函数。删除的模板更匹配 const int
左值 n
,因此它会导致 test
无法编译。如果您确实想要 func(d, n)
有效但对 n
没有影响的行为,只需取出已删除的模板即可。