此代码:
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
,所以他们可以说是兄弟。
C++ 的类型系统从内到外确定表达式的类型[1]。这意味着条件表达式的类型是在对
CardAbility*
赋值之前确定的,并且编译器必须仅选择 CardAbilityBurn*
和 CardAbilityEmpty*
。
由于 C++ 具有多重继承和一些更多可能的转换路径,因此没有一个类型是另一个类型的超类,因此编译就停止了。
要成功编译,您需要提供缺少的部分:将一个或两个操作数转换为基类类型,以便整个条件表达式可以采用该类型。
auto* cardAbility = contains
? static_cast<CardAbility*>(new CardAbilityBurn(i))
: static_cast<CardAbility*>(new CardAbilityEmpty );
(请注意 auto 的使用,因为您已经在右侧表达式中提供了目标类型。)
它有点复杂,所以最终
if
-else
结构更适合这种情况。
[1] 有一个例外:重载函数名称没有确定的类型,直到您将它们(隐式或显式)转换为它们的版本之一。
有针对 Microsoft 编译器描述的几种情况,如何处理操作数类型。
如果两个操作数的类型相同,则结果也是该类型。
如果两个操作数都是算术或枚举类型,通常的 执行算术转换(算术转换中介绍) 将它们转换为通用类型。
如果两个操作数都是指针类型,或者其中一个操作数是指针类型并且 other 是一个计算结果为 0 的常量表达式,指针转换为 执行将它们转换为通用类型。
如果两个操作数都是引用类型,则引用转换为 执行将它们转换为通用类型。
如果两个操作数都是 void 类型,则通用类型为 void 类型。
如果两个操作数都是相同的用户定义类型,则公共类型为 那种类型。
如果操作数具有不同类型且至少其中一个操作数 具有用户定义的类型,然后使用语言规则 确定常见类型。 (请参阅下面的警告。)
然后有一个警告:
如果第二个和第三个操作数的类型不相同,则 C++ 标准中指定的复杂类型转换规则是 调用。这些转换可能会导致意外行为,包括 临时物体的建造和破坏。为此,我们 强烈建议您 (1) 避免使用用户定义类型作为 带有条件运算符的操作数或 (2) 如果您确实使用 用户定义的类型,然后将每个操作数显式转换为通用的 类型。
可能这就是 Apple 在 LLVM 中停用此隐式转换的原因。
因此,if/else 似乎更适合您的情况。