通用引用,例如T&&
可以推断T
为“对象类型”或“引用类型”
在您的示例中,它可以推断T
为int
传递右值时,因此函数参数是int&&
,或者它可以推断T
为int&
传递左值时,在这种情况下,函数参数是int&
(因为参考折叠规则说std::add_rvalue_reference<int&>::type
is just int&
)
如果T
不是由函数调用推断出(如您的X::baz
示例中),则不能推断为int&
,因此该引用不是通用引用。
所以恕我直言,真的不需要新语法,它非常适合模板参数推导和引用折叠规则,只需稍加调整即可将模板参数推导出为引用类型(在 C++03 中,函数模板参数类型T
或者T&
总是推断T
为对象类型。)
这些语义和这种语法是从一开始就提出的,当时提出了右值引用和对参数推导规则的调整作为转发问题的解决方案,请参阅N1385。使用这种语法来提供完美的转发是在提出右值引用的同时提出的,目的是为了移动语义:N1377与 N1385在同一个邮件中。我认为从未认真提出过替代语法。
恕我直言,无论如何,另一种语法实际上会更加混乱。如果您有template<typename T> void bar(T&@)
通用引用的语法,但语义与我们今天的语义相同,那么在调用bar(i)
模板参数时T
可以推断为int&
orint
并且函数参数的类型为int&
or int&&
...两者都不是“ T&@
”(不管那个类型是什么。)所以你会有一个声明符的语言语法,T&@
它不是一个永远存在的类型,因为它实际上总是引用其他类型,要么int&
要么int&&
。
至少我们得到的语法T&&
是一个真正的类型,并且引用折叠规则并不特定于使用通用引用的函数模板,它们与模板之外的类型系统的其余部分完全一致:
struct A {} a;
typedef A& T;
T&& ref = a; // T&& == A&
或等效地:
struct A {} a;
typedef A& T;
std::add_rvalue_reference<T>::type ref = a; // type == A&
什么时候T
是左值引用类型,T&&
也是。我认为不需要新的语法,规则真的没有那么复杂或混乱。