不同编译器使用的不同铸造操作符

时间:2013-05-19 14:37:00

标签: c++ templates casting operator-overloading overload-resolution

以下C ++程序在我尝试的所有编译器中编译时都没有警告(gcc 4.6.3,llvm 3.0,icc 13.1.1,SolarisStudio 12.1 / 12.3):

struct CClass
{
  template<class T>
  operator T() const { return 1; }

  operator int() const { return 2; }
};

int main(void)
{
  CClass x;
  return static_cast<char>(x);
}

但是,除了SolarisStudio编译器之外的所有编译器都返回2,SolarisStudio(任一版本)返回1,我认为这是最合乎逻辑的结果。

使用return x.operator char();会导致所有编译器返回1。

显然,自从搞清楚后,我一直在使用后者的表示法。但是,我想知道哪些编译器是正确的以及为什么。 (人们会认为大多数规则,但这仍然不能解释为什么。)

此问题似乎与SO问题hereherehere有关,但这些“仅”解决了问题,没有解释(我能够无论如何都适用于我的特定问题。)

请注意,添加一个额外的重载转换运算符,比如operator float() const { return 3; }会导致除SolarisStudio之外的所有编译器都抱怨歧义。

2 个答案:

答案 0 :(得分:9)

应选择第一个(模板)重载

C ++ 11标准的第13.3.3 / 1段规定:

  

[...]一个可行的函数F1被定义为比另一个可行函数更好的函数   F2如果对于所有参数iICSi(F1)不是比ICSi(F2)更差的转换序列,那么

     

- 对于某些参数jICSj(F1)是比ICSj(F2)更好的转化序列,或者,如果没有,

     

- 上下文是按用户定义的转换初始化(参见8.5,13.3.1.5和13.3.1.6)和   从F1的返回类型到目标类型的标准转换序列(即,类型的   正在初始化的实体)是比标准转换序列更好的转换序列   返回类型F2到目标类型。 [示例

struct A {
    A();
    operator int();
    operator double();
} a;
int i = a; // a.operator int() followed by no conversion
           // is better than a.operator double() followed by
           // a conversion to int
float x = a; // ambiguous: both possibilities require conversions,
             // and neither is better than the other
     

- 结束示例]或如果不是

     

- F1是非模板函数,F2是函数模板特化,或者,如果不是,

     

[...]

正如您所看到的那样,第一个转换运算符是模板的事实仅在标准转换序列从其返回类型(在本例中为char)到目标类型({{1} },在这种情况下)优于标准转换序列,从非模板重载(在本例中为char)的返回类型到目标类型({{1在这种情况下)。

但是,从intchar的标准转换是完全匹配,而从charchar的标准转换不是。因此,§13.3.3/ 1的第三项不适用,第二项则适用。

这意味着应该选择第一个(模板)重载

答案 1 :(得分:5)

第一个是完全匹配,第二个需要转换。完全匹配优先于转换。

您链接的其他问题与您的无关。

一些建议:不要使用模板转换运算符。将其命名为convert_to