对象、右值引用和常量引用之间的重载决策

71
考虑到这三个函数,这个调用是模棱两可的。
int f( int );
int f( int && );
int f( int const & );

int q = f( 3 );

移除 f( int ) 会导致Clang和GCC都优先选择rvalue引用而不是lvalue引用。但是,移除任何一个引用重载都会导致 f( int ) 发生二义性。

通常情况下,重载解析是通过严格部分排序来进行的,但是 int 看起来等价于两个不相互等价的东西。这里有什么规则吗?我似乎记得有一个缺陷报告与此相关。

在未来的标准中,int && 是否可能优先于 int?引用必须绑定到初始化程序,而对象类型并没有如此限制。因此,在 TT && 之间进行重载可以有效地意味着“如果我已经拥有,则使用现有对象,否则进行复制”。(这类似于纯值传递,但节省了移动开销。)由于这些编译器当前的工作方式,这必须通过重载 T const &T && 并显式复制来完成。但我甚至不确定这是否严格符合标准。


你在代码中使用了 int&&,但在问题中却泛化为 T&&,尽管它们是不同的。到底是哪一个? - Rapptz
1
@Rapptz,我只是在谈论实际使用中可能的含义时说了“T”。我并不是要建议完美转发,那是完全不同的事情。 - Potatoswatter
1个回答

63
这里的规则是什么?
由于只有一个参数,规则是该参数的三种可行初始化中之一必须比其他两种都更匹配。当比较两个初始化时,要么一个比另一个更好,要么两者都无法区分。
如果没有关于直接引用绑定的特殊规则,所有三种提到的初始化都无法区分(在所有三个比较中)。
有关直接引用绑定的特殊规则使int &&优于const int &,但int既不更好也不更差。因此,没有最佳匹配。
S1    S2
int   int&&         indistinguishable
int   const int&    indistinguishable
int&& const int&    S1 better

int&&const int&更好,因为根据13.3.3.2:

S1和S2是引用绑定(8.5.3),都不是非静态成员函数的隐式对象参数,并且S1将rvalue引用绑定到rvalue,S2将lvalue引用绑定。

但是,当其中一个初始化不是引用绑定时,此规则不适用。

有没有可能在未来的标准中更喜欢使用int &&而不是int?引用必须绑定到初始化程序,而对象类型没有受到如此限制。因此,在T和T &&之间进行重载可以有效地意味着“如果我已经拥有所有权,请使用现有对象;否则,复制一个对象。”

您提议将引用绑定与非引用绑定相比更匹配。为什么不将您的想法发布到isocpp future proposals中呢?SO不是主观讨论/意见的最佳选择。


所以gcc和clang都是正确的:如果考虑f(int)f(int&&),则重载是模棱两可的,同样适用于f(int)f(int const&) - Yakk - Adam Nevraumont
5
几乎正确。如果没有最佳匹配项,函数重载就会产生歧义。假设对于调用 f(2.0)f(int)f(int&&)f(double) 都是可行的,那么 f(double) 就是最佳匹配项,即使 f(int)f(int&&) 也在考虑之中。 - Andrew Tomazos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接