为什么此条件运算符的计算结果为 int?

Why does this conditional operator evaluate to int?

我偶然发现了一个奇怪的(对我来说)行为。这是我的代码:

struct A 
{
  operator unsigned long long() const { return 1ull << 32; }
};

A a1;
unsigned long long a2 = 1ull << 32;

bool b = rand() % 2;
auto c1 = b ? a1 : 0;
auto c2 = b ? a2 : 0;

为什么 c1 属于 int 而不是 unsigned long long 类似于 c2?为什么没有生成转换警告(VC++)?

我花了一天时间才弄清楚我的应用程序出了什么问题。

这似乎符合 C++ 标准。

C++17 标准

来自 C++17 draft standard,第 8.16 节:

  1. If either the second or the third operand has type void, [...]
  2. Otherwise, if the second and third operand are glvalue bit-fields of the same value category, [...]
  3. Otherwise, if the second and third operand have different types and either has (possibly cv-qualified) class type, [...] an attempt is made to form an implicit conversion sequence (16.3.3.1) from each of those operands to the type of the other. [...] Attempts are made to form an implicit conversion sequence from an operand expression E1 of type T1 to a target type related to the type T2 of the operand expression E2 as follows

    1. If E2 is an lvalue, the target type is “lvalue reference to T2”, subject to the constraint that in the conversion the reference must bind directly to an lvalue
    2. If E2 is an xvalue, [...]
    3. If E2 is a prvalue or if neither of the conversion sequences above can be formed and at least one of the operands has (possibly cv-qualified) class type
      1. If T1 and T2 are the same class type (ignoring cv-qualification), [...]
      2. otherwise, the target type is the type that E2 would have after applying the lvalue-to-rvalue,array-to-pointer, and function-to-pointer standard conversions.

    Using this process, it is determined whether an implicit conversion sequence can be formed from the second operand to the target type determined for the third operand, and vice versa. If both sequences can be formed, or one can be formed but it is the ambiguous conversion sequence, the program is ill-formed. If no conversion sequence can be formed, the operands are left unchanged and further checking is performed as described below. Otherwise, if exactly one conversion sequence can be formed, that conversion is applied to the chosen operand and the converted operand is used in place of the original operand for the remainder of this section.

  4. If the second and third operands are glvalues of the same value category and have the same type, [...]
  5. Otherwise, the result is a prvalue. If the second and third operands do not have the same type, and either has (possibly cv-qualified) class type, [...]
  6. Lvalue-to-rvalue (7.1), array-to-pointer (7.2), and function-to-pointer (7.3) standard conversions are performed on the second and third operands. After those conversions, one of the following shall hold:

    1. The second and third operands have the same type; [...]
    2. The second and third operands have arithmetic or enumeration type; the usual arithmetic conversions are performed to bring them to a common type, and the result is of that type

    [...]

第一种情况:

A a1;
auto c1 = b ? a1 : 0;
  • 0int
  • 类型的纯右值
  • a1A
  • 类型的左值

规则 4 适用:

  • E1=0 到 E2=a1:尝试应用规则 4.1。目标类型是 A&。但是,没有从 int 到左值 A&.
  • 的隐式转换
  • E1=a1 到 E2=0:适用规则 4.3.2。目标类型是 int。有一个隐式转换,使用 A::operator unsigned long long().

因此根据规则 4,此条件表达式的 return 类型为 int.

第二种情况:

unsigned long long a2 = 1ull << 32;
auto c2 = b ? a2 : 0;
  • 0int
  • 类型的纯右值
  • a2unsigned long long
  • 类型的左值

规则7.2适用:条件运算符的return类型由两个表达式的算术转换规则决定。这是 unsigned long long.

关于编译器警告

两个 clang(demo) and g++ (demo) will raise a warning with the option -Wconversion. I've no experience of MSVC, but it also seems to have warnings for dangerous arithmetic conversions: C4242, C4365。检查你是否启用了它们。