转发参考:给定 T&& 时返回 T&& 和给定 T&&时返回 T&
Forwarding reference: returning T when given T&& and T& when given T&
考虑一个类A
,我如何编写具有相同行为的模板
A& pretty(A& x)
{
/* make x pretty */
return x;
}
A pretty(A&& x)
{
/* make x pretty */
return x;
}
知道我想:
- 以
完全相同的方式修改参数(
x
(,无论参数是右值引用还是左值引用(实际上,两个部分/* make x pretty */
相同(,因此具有单个函数;避免不必要的复制;
能够使用该函数修改变量;
能够"管道"函数调用,无论参数是右值还是左值。
作为 3. 和 4. 的示例,请考虑以下用例:
void read_A(const A& x) { /* ... */ }
void take_A(A&& x) { /* ... */ }
A x();
read_A(pretty(x));
take_A(pretty(A()));
我的想法是利用转发引用,同时将允许的参数限制为对A
的引用。但是返回类型呢?
template<typename T>
std::enable_if_t<std::is_same<T, A>::value>
/*???*/ pretty(T&& x)
{
/* make x pretty */
return x; //?
}
为什么不干脆写
#include <iostream>
template <class T>
T somefunc(T&& a) {
/* do something with a */
std::cout << __PRETTY_FUNCTION__ << 'n';
return std::forward<T>(a);
}
int main(int argc, char* argv[]) {
int a = 5;
somefunc(a);
somefunc(5);
return 0;
}
哪个会返回
T somefunc(T &&) [T = int &]
T somefunc(T &&) [T = int]
如您所见,这些函数具有您想要的签名。在第一次调用中,T
得到 int &
,因此返回值 int &
。在第二个中,你有 T = int = int &&
,这又是你想要的。
顺便说一下,您最初考虑应用 std::is_same
来禁用A
以外的类型的重载解析似乎也是错误的。根据cpp偏好,
如果
T
和U
命名具有相同常量易失性限定条件的相同类型,则提供等于true
的成员常量值。否则,值为false
。
因此,您可能希望使用类似 decay
,或者至少是remove_cv
和remove_reference
的组合来应用您想要的逻辑。下面是上述代码的修改版本,现在包括重载解析启用程序。
#include <iostream>
#include <type_traits>
template <class T> T somefunc(T &&a) {
/* do something with a */
std::cout << __PRETTY_FUNCTION__ << 'n';
return std::forward<T>(a);
}
template <class T, typename std::enable_if<
std::is_same<typename std::decay<T>::type, float>::value,
int>::type = 0>
T onlyfloat_correct(T &&a) {
/* do something with a */
std::cout << __PRETTY_FUNCTION__ << 'n';
return std::forward<T>(a);
}
template <class T,
typename std::enable_if<std::is_same<T, float>::value, int>::type = 0>
T onlyfloat_wrong(T &&a) {
/* do something with a */
std::cout << __PRETTY_FUNCTION__ << 'n';
return std::forward<T>(a);
}
int main(int argc, char *argv[]) {
int a = 5;
const float b = 5;
somefunc(a);
somefunc(5);
onlyfloat_correct(b);
// onlyfloat_wrong(b);
return 0;
}
这里根本不需要模板。 您可以利用右值引用是右值引用重载中所有调用pretty
的左值这一事实,因此您只需在左值重载中对make x pretty
逻辑进行编码。 那看起来像
A& pretty(A& x)
{
/* make x pretty */
return x;
}
A pretty(A&& x)
{
return std::move(pretty(x));
}
相关文章:
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 什么时候在C++中返回常量引用是个好主意
- 你能重载对象变量名本身返回的内容吗
- 为什么 Serial.println(<char[]>);返回随机字符?
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何获取std::result_of函数的返回类型
- QueryWorkingSet总是返回false
- (C++)分析树以计算返回错误值的简单算术表达式
- 返回值的完美转发?
- 类似函数的化简函数中的转发和返回类型
- 如何声明接受转发引用并返回引用或副本的函数模板
- 为什么 VS C++链接器返回具有混合 DLL 转发的"LNK2001: unresolved external symbol"?
- 为什么需要转发返回值
- 转发参考:给定 T&& 时返回 T&& 和给定 T&&时返回 T&
- 使用auto&&完美转发返回值
- 从转发函数类型推断的模板化返回类型
- 转发通用可可对象的返回值
- 返回转发的引用
- 返回转发引用参数 - 最佳做法
- C++抽象的基本模板,用于使用协变返回进行转发