右值参数的模板类型推断

Template type deduction for rvalue arguments

本文关键字:类型 值参 参数      更新时间:2023-10-16

我了解 C++11 中的转发方法。

template <class T> void foo(T &&)

FOO 现在将同时接受左值和右值。

我的问题是当我进一步超载 foo 时。考虑以下简单代码:

template <class T> class A {};
template <class T> void foo(T &&obj) {}
template <class T> void foo(A<T> &&obj) {}
int main() {
  int i;
  A<int> a;
  foo(i); // calls foo(T &&) as I want
  foo(a); // calls foo(T &&), but I want it to call foo(A<T> &&)
  return 0;
}

如果我使用 A < int > &(左值)对象调用foo,它将调用 foo(T &&) ,而不是 foo(A < T > &&) 。在foo(T &&obj)的定义中,我设法用 std 和自定义特征来区分obj是否A<T>,但这会产生非常非常混乱的代码,因为我必须从 obj 调用 A 方法,并且obj被声明为 T ,而不是 A < T > 。重新排序声明或添加左值重载并不能解决问题。

希望我能理解自己。我提供了一个简化的代码,以便在问题中分区。我正在实现一个自定义Optional < T >类(类似于boost::optional),我在构造函数中遇到了这个问题,因为我需要能够从另一个Optional < T >Optional < U >TU对象创建(和分配)一个Optional < T >对象。(其中T是要创建的可选对象持有的类型,U是可转换为T的不同类型)。

谢谢你的时间。

在函数调用的模板参数推导期间,"通用引用"的特殊规则仅在参数类型为 cv 非限定模板参数 [temp.deduct.call]/3 时适用

[ P 是函数模板的参数类型,A 是参数的类型]

如果 P 是对 cv 非限定模板参数的右值引用,并且参数是左值,则使用类型"对 A 的左值引用"代替类型推导的A。[示例:

template <class T> int f(T&&);
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&), which
// would bind an rvalue reference to an lvalue

结束示例 ]

同样,这些规则不适用于参数类型 A<T>&& 。它不是"通用引用",而纯粹是右值引用类型。


如果你想在两个构造函数之间进行排名,其中A<T> -version 应该更专业(更好的匹配),你可以:

  • 除了T&&通用版本外,还提供两个三个重载A<T> const&A<T>&(感谢 Eric Niebler)和 A<T>&&
  • 使用 SFINAE;提供两个带有参数T&&的重载,并检查T是否是 A<T> 的专用化