fre*_*low 24 c++ language-design rvalue-reference c++11 forwarding-reference
这是一个右值参考:
void foo(int&& a);
Run Code Online (Sandbox Code Playgroud)
它不绑定到左值:
int i = 42;
foo(i); // error
Run Code Online (Sandbox Code Playgroud)
这是一个普遍的参考:
template<typename T>
void bar(T&& b);
Run Code Online (Sandbox Code Playgroud)
它绑定到右值,它也绑定到左值:
bar(i); // okay
Run Code Online (Sandbox Code Playgroud)
这是一个右值参考:
template<typename T>
struct X
{
void baz(T&& c);
};
Run Code Online (Sandbox Code Playgroud)
它不绑定到左值:
X<int> x;
x.baz(i); // error
Run Code Online (Sandbox Code Playgroud)
为什么通用引用使用与右值引用相同的语法?这不是一个不必要的混乱来源吗?难道该委员会曾经考虑替代语法像T&&&,T&*,T@或T&42(开玩笑的对最后一个)?如果是这样,拒绝替代语法的原因是什么?
Jon*_*ely 21
通用引用,例如T&&可以推断T为" 对象类型 "或" 引用类型 "
在你的例子中,它可以推导T为int当传递一个rvalue时,所以函数参数是int&&,或者它可以推导T为int&传递左值时,在这种情况下函数参数是int&(因为参考折叠规则说std::add_rvalue_reference<int&>::type的只是int&)
如果T函数调用没有推导出(如在你的X::baz例子中)那么它不能推导出来int&,因此引用不是通用引用.
所以恕我直言,真的不需要新的语法,它很适合模板参数推导和参考折叠规则,小调整模板参数可以推导为参考类型(其中在C++ 03中的函数模板参数类型T或者T&总是推断T为对象类型.)
这些语义和这种语法是从一开始就提出的,当时rvalue引用和对参数推导规则的调整被提议作为转发问题的解决方案,参见N1385.为了移动语义的目的,提出了使用这种语法提供完美转发的同时提出rvalue引用:N1377与N1385在同一邮件中.我认为没有认真提出替代语法.
恕我直言,另一种语法实际上会更加令人困惑.如果您具有template<typename T> void bar(T&@)通用引用的语法,但具有与我们今天相同的语义,那么在调用bar(i)模板参数时T可以推断为int&或者int函数参数是类型int&或者int&&......两者都不是" T&@"(无论那种类型是什么.)所以你在语言中有语法用于声明器T&@,它不是一种可以存在的类型,因为它实际上总是引用其他类型,int&或者int&&.
至少在我们得到的语法类型T&&是真实类型的情况下,参考折叠规则并不特定于使用通用引用的函数模板,它们与模板之外的其他类型系统完全一致:
struct A {} a;
typedef A& T;
T&& ref = a; // T&& == A&
Run Code Online (Sandbox Code Playgroud)
或等效地:
struct A {} a;
typedef A& T;
std::add_rvalue_reference<T>::type ref = a; // type == A&
Run Code Online (Sandbox Code Playgroud)
何时T是左值引用类型,T&&也是.我认为不需要新的语法,规则确实不那么复杂或令人困惑.
为什么通用引用使用与右值引用相同的语法?这不是不必要的混乱根源吗?委员会是否曾经考虑过其他语法...
是的,这令人困惑,IMO(我在这里不同意@JonathanWakely)。我记得在一次非正式讨论(我想是午餐)时,我们确实讨论了不同的符号(Howard Hinnant和Dave Abrahams在那里提出了他们的想法,而EDG的家伙们正在就如何适应它提供反馈)在核心语言中;这早于N1377)。我想我记得&?并&|&&曾考虑过,但所有这些都是口头的;我不知道会议记录已被使用(但我相信这也是John建议使用&&用于右值引用)。但是,这些只是设计的早期阶段,当时有很多基本的语义问题需要考虑。(例如,在同一顿午餐讨论中,我们还提出了不使用两种参考,而是使用两种参考参数的可能性。)
在“类模板参数推导”(P0099R3)的C ++ 17功能中找到了引起这种混乱的一个较新的方面。通过转换构造函数和构造函数模板的签名来形成功能模板签名。对于类似:
template<typename T> struct S {
S(T&&);
};
Run Code Online (Sandbox Code Playgroud)
功能模板签名
template<typename T> auto S(T&&)->S<T>;
Run Code Online (Sandbox Code Playgroud)
形成用于推导类似的声明
int i = 42;
S s = i; // Deduce S<int> or S<int&>?
Run Code Online (Sandbox Code Playgroud)
推论T = int&这里是违反直觉的。因此,在这种情况下,我们必须添加“特殊扣除规则以禁用特殊扣除规则” :-(
| 归档时间: |
|
| 查看次数: |
1957 次 |
| 最近记录: |