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) 成功编译相同的代码,没有任何错误或警告。

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

最佳答案

长话短说; 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/48751319/

相关文章:

c++ - 是否可以将运算符用作映射中的映射值?

c++ - 性能报告显示此函数 "__memset_avx2_unaligned_erms"有开销。这是否意味着内存未对齐?

c++ - 如何将 n 个参数传递给 n 未知的函数

c++ - 正确实现 WlanHostedNetwork 函数的 WlanSetSecuritySettings

c++ - 我可以在算术表达式中调用构造函数吗?

java - 将整数数组转换为单个字符串

c++ - 运算符优先级 C++ |进行计算的确切顺序是什么?

c# List.Exists 返回 true "false && true"

c++ - 将字符串转换为 double 保持四舍五入到整数

c - GCC 不在 printf 中进行默认类型转换