rvalue参数的模板类型推导

时间:2013-11-03 22:47:44

标签: c++ templates c++11 overloading rvalue

我理解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;
}

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

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

感谢您的时间。

1 个答案:

答案 0 :(得分:6)

在函数调用的模板参数推导期间,“通用引用”的特殊规则仅在参数类型为cv-unqualified模板参数[temp.deduct.call] / 3

时适用。

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

  

如果P是对cv-nonqualified模板参数的右值引用,并且参数是左值,则使用“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> - 版本应该更专业(更好的匹配),你可以:

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