【问题标题】:Different casting operators used by different compilers不同编译器使用的不同类型转换运算符
【发布时间】:2013-05-14 04:51:40
【问题描述】:

以下 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 之外的所有编译器都抱怨歧义。

【问题讨论】:

  • 刚刚在我的编译器 G++ 4.8.0 中测试过,它返回 1。
  • G++ 4.7.2 也返回 1。对于 operator float(),没有任何歧义的抱怨。
  • g++ 返回一个从 4.7 开始的 gcc.godbolt.org
  • 这是糟糕的代码。避免使用通用(非专业或非限制 [例如通过 std::enable_if&lt;&gt;])模板转换运算符,因为这些可能会导致不必要的和不可预见的转换。

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


【解决方案1】:

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

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,在本例中)到目标类型(char,在本例中case)优于从非模板重载的返回类型(在本例中为int)到目标类型(在本例中为char)的标准转换序列。

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

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

【讨论】:

  • 并非如此。它表示将选择一个模板 specialization。但在 op 的情况下,没有专业化。编译器甚至不会开始创建模板,因为它已经找到了可以使用的匹配的非模板转换。仅当显式调用模板或没有其他匹配的重载时才会创建模板。编译器没有理由在匹配的模板上开始“猜测”
  • @YochaiTimmer:不,那不是真的。它不会实例化模板,但会执行模板参数推导并查看模板是否是重载解决方案的可行候选者。如果结果证明这是最佳可行的候选者,它将选择它并实例化它
【解决方案2】:

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

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

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

【讨论】:

  • +1 用于警告模板转换运算符。也许您可以添加一些解释为什么这是危险的。
猜你喜欢
  • 2014-10-04
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2014-07-28
  • 2020-11-09
  • 2012-01-09
  • 2018-05-22
  • 1970-01-01
相关资源
最近更新 更多