为什么对于左值,明确选择左值引用重载而不是转发引用重载?

Mik*_*ail 14 c++ templates overloading forwarding-reference

看一下这两个重载的函数模板:

template <class T>
int foo(T& x) {  // #1
  return 1;
}
template <class T>
int foo(T&& x) {  // #2
  return 2;
}
Run Code Online (Sandbox Code Playgroud)

foo通过以下方式调用:

int i;
foo(i);  // calls #1
Run Code Online (Sandbox Code Playgroud)

并且明确选择了重载#1:https ://gcc.godbolt.org/z/zchK1zxMW

这似乎是一个正确的行为,但我无法理解为什么会发生(而且我实际上有代码,这不是我所期望的)。

过载分辨率

如果任何候选者是函数模板,则其特化是使用模板参数推导生成的,并且此类特化被视为与非模板函数一样,除非在决胜规则中另有指定。

好的,让我们生成专业化。对于#1来说,这很容易,它就变成了int foo(int& x)。对于 #2,适用特殊扣除规则,因为它是转发参考。i是一个左值,因此T被推导为int&T&&变为int& &&,在引用折叠后变为 just int&,产生结果int foo(int& x)。这与#1 完全相同!

所以我希望看到一个不明确的调用,但这并没有发生。谁能解释一下为什么吗?这里使用什么决定因素来选择最佳可行的功能?

另请参阅Slack 中的相关讨论,其中有一些想法。

Yak*_*ont 4

非语言律师的回答是,对于这种情况,有一个平局规则。

充分理解标准措辞来解码它需要一个简短的书章。但是,当推导T&&T&重载之间选择左值和其他所有选项时,T&获胜者。

这样做是有意为之:(a)使通用引用起作用,同时(b)如果您想单独处理左值引用,则允许您重载它们。

平局断路器来自模板函数重载“更专业”的排序规则。T*与指针相比,同样的原因T,即使 和T=Foo*T=Foo给出相同的函数参数。模板参数发生二次排序,并且T可以模拟T*手段的事实T*更加专门化(或者更确切地说不是,标准中的措辞很尴尬)。T&声明左值节拍的额外规则T&&位于同一部分。