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

时间:2015-04-24 08:13:37

标签: c++ ternary-operator

此代码:

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

给了我以下错误:

  

不兼容的操作数类型CardAbilityBurn和CardAbilityEmpty

但是如果我写这样的代码:

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

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

我需要注意(我认为您可能需要此信息),CardAbilityEmptyCardAbilityBurn都来自CardAbility所以他们可以这样说兄弟。

由于

2 个答案:

答案 0 :(得分:16)

C ++的类型系统确定表达式'从里到外的类型 [1] 。这意味着条件表达式的类型是在分配给CardAbility*之前确定的,编译器必须只选择CardAbilityBurn*CardAbilityEmpty*

由于C ++具有多重继承和更多可能的转换路径,因为没有一种类型是另一种类型的超类,编译就会停止。

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

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

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

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

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

答案 1 :(得分:2)

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

  

如果两个操作数的类型相同,则结果属于该类型。

     

如果两个操作数都是算术类型或枚举类型,则通常   执行算术转换(在算术转换中涵盖)   将它们转换为普通类型。

     

如果两个操作数都是指针类型,或者一个是指针类型,那么   other是一个常量表达式,计算结果为0,指针转换为   执行以将它们转换为通用类型。

     

如果两个操作数都是引用类型,则引用转换为   执行以将它们转换为通用类型。

     

如果两个操作数都是void类型,则常见类型为void。

     

如果两个操作数具有相同的用户定义类型,则通用类型为   那种类型。

     

如果操作数具有不同的类型和至少一个操作数   具有用户定义的类型,然后使用语言规则   确定常见类型。 (见下面的警告。)

然后有一个警告:

  

如果第二个和第三个操作数的类型不相同,那么   复杂类型转换规则,如C ++标准中所规定的那样   调用。这些转换可能会导致意外行为,包括   建造和销毁临时物品。出于这个原因,我们   强烈建议您(1)避免使用用户定义的类型   带条件运算符的操作数或(2)如果使用   用户定义的类型,然后显式地将每个操作数转换为公共   类型。

可能原因是,Apple在LLVM中停用了这种隐式转换。

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