此代码:
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;
}
那么编译器并不介意。为什么这样?我想使用三元条件运算符,因为它只是一行。那有什么不对?
我需要注意(我认为您可能需要此信息),CardAbilityEmpty
和CardAbilityBurn
都来自CardAbility
所以他们可以这样说兄弟。
由于
答案 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似乎更适合你的情况。