考虑以下代码:
#include <cstdio>
struct S {
S(int) {}
};
void f(const S&) { std::puts("const S&"); }
void f(S&&) { std::puts("S&&"); }
int main() {
f(42);
}
很明显,GCC and Clang agree应该调用S&&
重载,但是我对标准的理解是,实际上没有规则要求这种情况!
当然,您会说对f
的调用必须初始化一个临时S
对象,并且重载解析更倾向于将右值引用绑定到右值而不是绑定左值引用。但是,这是[over.ics.rank] /(3.2)中的标准实际所说的:
如果
,标准转换顺序S1
比标准转换顺序S2
更好。...
S1
和S2
是引用绑定(11.6.3),都没有引用未声明 ref-qualifier 声明的非静态成员函数的隐式对象参数。 ,而S1
将右值引用绑定到右值,而S2
则将左值引用绑定...
因此,此与左值和右值引用绑定有关的决胜局仅适用于标准转换序列。但是,在给定f
的情况下,为了调用int
的任一重载,都需要一个用户定义的转换序列。对用户定义的转换序列进行排名的规则是(3.3),
如果用户定义的转换序列
U1
包含相同的用户定义的转换函数或构造函数,或者它们在相同的类中初始化相同的类,则它们比另一个用户定义的转换序列U2
更好。聚合初始化,无论哪种情况,U1
的第二个标准转换序列都比U2
的第二个标准转换序列好。
很明显,两个转换序列(到const S&
和S&&
)都调用相同的构造函数,因此,如果第二个标准转换比第一个标准转换更好,则第二个转换序列可能会比第一个更好。但是,[over.ics.ref] / 2说:
当引用类型的参数未直接绑定到参数表达式时,转换序列是根据16.3.3.1。将参数表达式转换为引用类型所需的序列。从概念上讲,此转换序列对应于使用参数表达式对引用类型的临时变量进行复制初始化。顶级简历的任何差异都归因于初始化,并不构成转换。
根据我的理解,从int
到const S&
的隐式转换顺序与从int
到const S
的用户定义的转换顺序相同,即只是一个用户定义的转换,第二个标准转换是身份转换;同样,从int
到S&&
的隐式转换序列与从int
到S
的用户定义转换序列相同,这也是具有以下内容的单个用户定义转换:第二个标准转换是身份转换。
因此,第二种重载的“显而易见”选择没有文字依据……还是我缺少的一种?