以下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问题here,here和here有关,但这些“仅”解决了问题,没有解释(我能够无论如何都适用于我的特定问题。)
请注意,添加一个额外的重载转换运算符,比如operator float() const { return 3; }
会导致除SolarisStudio之外的所有编译器都抱怨歧义。
答案 0 :(得分:9)
应选择第一个(模板)重载。
C ++ 11标准的第13.3.3 / 1段规定:
[...]一个可行的函数
F1
被定义为比另一个可行函数更好的函数F2
如果对于所有参数i
,ICSi(F1)
不是比ICSi(F2)
更差的转换序列,那么- 对于某些参数
j
,ICSj(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在这种情况下)。
但是,从int
到char
的标准转换是完全匹配,而从char
到char
的标准转换不是。因此,§13.3.3/ 1的第三项不适用,第二项则适用。
这意味着应该选择第一个(模板)重载。
答案 1 :(得分:5)
第一个是完全匹配,第二个需要转换。完全匹配优先于转换。
您链接的其他问题与您的无关。
一些建议:不要使用模板转换运算符。将其命名为convert_to
。