c++ - 三元运算符的奇怪隐式转换

标签 c++ type-conversion operator-keyword implicit-conversion ternary

我有以下代码:

class A {
public:
    operator int() const { return 5; }
};

class B {
public:
    operator int() const { return 6; }
};

int main() {
    A a;
    B b;
    int myInt = true ? a : b;
    return 0;
}

尝试使用 Visual Studio 2017 RC 编译该代码会导致以下错误:

error C2446: :: no conversion from B to A

note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

...这很令人惊讶,因为我希望它将它们都转换为通用类型,在本例中为 int

clang (4.0) 成功编译相同的代码,没有任何错误或警告。

在这种情况下,两者中哪一个是正确的,为什么?

最佳答案

TL;DR; clang是正确的,因为 A 之间没有可能的转换和 B ,重载决议用于确定要应用于操作数的转换,并选择以下(虚构的)重载运算符:

int operator?:(bool, int, int);

?: 存在这样的(又是虚构的)过载。任何一对算术类型的运算符(请参阅下面的引用资料)。


标准规则:

由于您无法转换 ABBA ,则以下适用:

[expr.cond]

Otherwise, the result is a prvalue. If the second and third operands do not have the same type, and either has (possibly cv-qualified) class type, overload resolution is used to determine the conversions (if any) to be applied to the operands ([over.match.oper], [over.built]). If the overload resolution fails, the program is ill-formed. Otherwise, the conversions thus determined are applied, and the converted operands are used in place of the original operands for the remainder of this subclause.

这又回到了这个:

[over.match.oper]

If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator.

[...]

The set of candidate functions for overload resolution is the union of the member candidates, the non-member candidates, and the built-in candidates.

If a built-in candidate is selected by overload resolution, the operands of class type are converted to the types of the corresponding parameters of the selected operation function, except that the second standard conversion sequence of a user-defined conversion sequence is not applied. Then the operator is treated as the corresponding built-in operator and interpreted according to [expr.compound].

在你的情况下,有一个内置的候选人:

[over.built#27]

For every pair of promoted arithmetic types L and R, there exist candidate operator functions of the form

LR      operator?:(bool, L, R);

where LR is the result of the usual arithmetic conversions ([expr.arith.conv]) between types L and R. [ Note: As with all these descriptions of candidate functions, this declaration serves only to describe the built-in operator for purposes of overload resolution. The operator “?:” cannot be overloaded. — end note ]


额外细节:

自从 ?:运算符不能重载,这意味着您的代码只有在两种类型都可以转换为算术类型时才有效(例如,int)。作为“反”示例,以下代码格式错误:

struct C { };
struct A { operator C() const; };
struct B { operator C() const; };

auto c = true ? A{} : B{}; // error: operands to ?: have different types 'A' and 'B'

另请注意,如果其中一种类型可转换为两种不同的算术类型,例如 int,您会得到一个模棱两可的“调用”。和 float :

struct A { operator int() const; };
struct B { 
    operator int() const; 
    operator float() const;
};

auto c = true ? A{} : B{};

错误(来自gcc)实际上充满了信息:

error: no match for ternary 'operator?:' (operand types are 'bool', 'A', and 'B')

auto c = true ? A{} : B{};
~~~~~^~~~~~~~~~~
  • note: candidate: operator?:(bool, float, int) <built-in>
  • note: candidate: operator?:(bool, float, float) <built-in>

关于c++ - 三元运算符的奇怪隐式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41637152/

相关文章:

c++ - 通过计算或转换在 C++ 中来回转换 2 的值的补码?

c++ - 如何判断 "->"运算符最终是否返回类型?

C++ 强制转换运算符重载和多态性

c++ - 使用列表/迭代器 (C++) 的愚蠢编译错误

c++ - 返回引用的导出函数

c++ - C++中的类数据库搜索算法

c# - 在 C# 中重载 = 运算符

c++ - 在 Windows 上使用适用于 C++ 的 Google API 客户端库

java - 如何从十六进制字节获取有符号的32位整数,而不在java中应用2的补码

c++ - 我可以告诉 C++ 编译器如何自己进行任意类型转换吗?