使用三元条件运算符时不兼容的操作数类型

Incompatible operand types when using ternary conditional operator

此代码:

  bool contains = std::find(indexes.begin(), indexes.end(), i) != indexes.end();
  CardAbility* cardAbility = contains ? new CardAbilityBurn(i) : new CardAbilityEmpty;

给我以下错误:

Incompatible operand types CardAbilityBurn and CardAbilityEmpty

但是如果我这样写代码:

 if (contains)
 {
    cardAbility = new CardAbilityBurn(i);
 }
 else
 {
    cardAbility = new CardAbilityEmpty;
 }

那么编译器不介意。为什么这样?我想使用三元条件运算符,因为它只有一行。那里出了什么问题?

我需要注意(我想你可能需要这些信息)CardAbilityEmptyCardAbilityBurn 都派生自 CardAbility 所以他们可以说是兄弟。

谢谢

several cases described for Microsoft compilers,如何处理操作数类型。

If both operands are of the same type, the result is of that type.

If both operands are of arithmetic or enumeration types, the usual arithmetic conversions (covered in Arithmetic Conversions) are performed to convert them to a common type.

If both operands are of pointer types or if one is a pointer type and the other is a constant expression that evaluates to 0, pointer conversions are performed to convert them to a common type.

If both operands are of reference types, reference conversions are performed to convert them to a common type.

If both operands are of type void, the common type is type void.

If both operands are of the same user-defined type, the common type is that type.

If the operands have different types and at least one of the operands has user-defined type then the language rules are used to determine the common type. (See warning below.)

然后有一个注意事项:

If the types of the second and third operands are not identical, then complex type conversion rules, as specified in the C++ Standard, are invoked. These conversions may lead to unexpected behavior including construction and destruction of temporary objects. For this reason, we strongly advise you to either (1) avoid using user-defined types as operands with the conditional operator or (2) if you do use user-defined types, then explicitly cast each operand to a common type.

可能这就是 Apple 在 LLVM 中停用此隐式转换的原因。

所以,if/else 似乎更适合你的情况。

C++'s type system determines expressions' 类型由内而外[1]。这意味着条件表达式的类型在对 CardAbility* 进行赋值之前就已确定,编译器只需选择 CardAbilityBurn*CardAbilityEmpty*.

由于 C++ 具有多重继承和一些更多可能的转换路径,因为 none 类型是其他类型的超 class,编译就此停止。

要成功编译,您需要提供缺少的部分:将一个或两个操作数转换为基础 class 类型,以便整个条件表达式可以采用该类型。

auto* cardAbility = contains
    ? static_cast<CardAbility*>(new CardAbilityBurn(i))
    : static_cast<CardAbility*>(new CardAbilityEmpty  );

(注意 auto 的使用,因为您已经在右侧表达式中提供了目标类型。)

但是有点复杂,所以最终if-else结构更适合这种情况。

[1] 有一个例外:重载的函数名称没有确定的类型,直到您将它们(隐式或显式)转换为它们的版本之一。