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

问题描述 投票:0回答:2

此代码:

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++ conditional-operator
2个回答
22
投票

C++ 的类型系统从内到外确定表达式的类型[1]。这意味着条件表达式的类型是在对

CardAbility*
赋值之前确定的,并且编译器必须仅选择
CardAbilityBurn*
CardAbilityEmpty*

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

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

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

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

有点复杂,所以最终

if
-
else
结构更适合这种情况。

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


2
投票

针对 Microsoft 编译器描述的几种情况,如何处理操作数类型。

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

如果两个操作数都是算术或枚举类型,通常的 执行算术转换(算术转换中介绍) 将它们转换为通用类型。

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

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

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

如果两个操作数都是相同的用户定义类型,则公共类型为 那种类型。

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

然后有一个警告:

如果第二个和第三个操作数的类型不相同,则 C++ 标准中指定的复杂类型转换规则是 调用。这些转换可能会导致意外行为,包括 临时物体的建造和破坏。为此,我们 强烈建议您 (1) 避免使用用户定义类型作为 带有条件运算符的操作数或 (2) 如果您确实使用 用户定义的类型,然后将每个操作数显式转换为通用的 类型。

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

因此,if/else 似乎更适合您的情况。

© www.soinside.com 2019 - 2024. All rights reserved.