具有多个函数和多个转换运算符的重载解决方案

Posted

技术标签:

【中文标题】具有多个函数和多个转换运算符的重载解决方案【英文标题】:Overload resolution with multiple functions and multiple conversion operators 【发布时间】:2016-07-04 09:02:33 【问题描述】:

考虑简单的代码:

#include<iostream>

struct A 
    operator double()
        std::cout<<"Conversion function double chosen."<<std::endl;
        return 1.1;
    
    operator char()
        std::cout<<"Conversion function char chosen."<<std::endl;
        return 'a';
    
 a;

void foo(int)
void foo (char)
int main() 
    foo(a);

上面的代码运行良好,正如预期的那样,gcc、clang 和 VC++ 选择了foo(char)

现在让我们稍微修改一下代码:

#include<iostream>

struct A 
    operator double()
        std::cout<<"Conversion function double chosen."<<std::endl;
        return 1.1;
    
    operator char()
        std::cout<<"Conversion function char chosen."<<std::endl;
        return 'a';
    
 a;

void foo(int)
void foo (double) //parameter changed from char to double
int main() 
    foo(a);

现在应该选择foo(double),但似乎只有 VC++ 对代码满意,而 clang 和 gcc 对上述代码不满意。

main.cpp:11:10: error: call of overloaded 'foo(A&)' is ambiguous
 foo(a);
     ^
main.cpp:8:6: note: candidate: void foo(int)
 void foo(int)
      ^
main.cpp:9:6: note: candidate: void foo(double)
 void foo (double) //parameter changed from char to double
      ^

谁能解释为什么上面的代码会失败?还是错误?。

再问一个问题:gcc和clang共享重载解析的代码吗?

【问题讨论】:

1:定义“不快乐”。 2:如果你删除foo(int)会发生什么? @Amit unhappy 表示代码被拒绝,至于删除函数foo(int),这不是问题的一部分,您可以自己尝试。 @AngelusMortis:VC++选择哪个函数? 【参考方案1】:

A -&gt; charA -&gt; char

A -&gt; intA -&gt; char -&gt; int(因为 charint 是一种提升,因此优于 doubleint 的转换)。

A -&gt; doubleA -&gt; double

两个用户定义的转换序列只有在它们涉及相同的用户定义的转换函数时才具有可比性。因此,A -&gt; char 是比A -&gt; int 更好的转换序列,因此您的第一种情况是明确的。 A -&gt; intA -&gt; double 都不比另一个好,所以第二种情况是模棱两可的。

【讨论】:

【参考方案2】:

TL;DR:不同之处在于,在第一种情况下,与第二种情况相反,用户定义的转换序列(A -&gt; charA -&gt; int)调用相同的转换函数( operator char)。这使我们能够通过 [over.ics.rank]/(3.3) 打破平局。


[over.match.best]/(1.4) 为特定函数选择最佳转换运算符(比较它们的返回类型的转换序列)。

因此,foo(int) 的更好转换函数是 operator char,然后提升到 int,而不是 operator double,然后进行浮点转换。

现在考虑第二个重载的两种变体:

    foo(char) 的最佳 ICS 是 也可以通过 operator char(身份比浮点转换更好)。因此[over.ics.rank]/(3.3) 适用:

    用户定义的转换序列U1 是比另一个用户定义的转换序列U2 更好的转换序列如果它们包含相同的用户定义的转换函数 [...] 并且在任何一种情况下U1的第二个标准转换序列优于U2的第二个标准转换序列。

    因此,整体转换为F2 被认为更好,因此被选中。

    foo(double) 的最佳 ICS 是通过operator double。我们最终得到两个使用不同转换函数的转换序列;没有什么是真正适用的,我们只是模棱两可。

【讨论】:

以上是关于具有多个函数和多个转换运算符的重载解决方案的主要内容,如果未能解决你的问题,请参考以下文章

为啥具有相同名称但不同签名的多个继承函数不会被视为重载函数?

模板类运算符重载多个类型名 C++

C++之重载运算与类型转换

[C++]——函数的重载

使用函数指针解决函数重载二义性调用问题

C#,多个 == 运算符重载,没有模棱两可的空值检查