c++ - 三元运算符中的 integral_constants

标签 c++ language-lawyer

MSVC 和 clang/gcc 对于是否可以在三元运算符中使用两个不同的整型常量(以及它们是否具有 common_type)存在分歧:

#include <utility>

int main()
{
    return false
        ? std::integral_constant<int, 1>() 
        : std::integral_constant<int, 2>();
}

上面的代码片段在 clang 和 gcc 中编译得很好,但在 MSVC 中却不行。根据标准,正确的行为是什么?如果是 clang/gcc 行为,那么用于推断这两种不同类型的公共(public)类型的转换序列是什么?

最佳答案

tldr;代码格式正确。条件表达式的类型为 int和值(value)2 .这是一个 MSVC 错误。


来自 [expr.cond]:

Otherwise, if the second and third operand have different types and either has (possibly cv-qualified) class type, or [...], an attempt is made to form an implicit conversion sequence (13.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: [...]
— If E2 is an lvalue, [...]
— If E2 is an xvalue, [...]
— 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:
      — if T1 and T2 are the same class type (ignoring cv-qualification), or one is a base class of the other, and T2 is at least as cv-qualified as T1, the target type is T2,
      — otherwise, the target type is the type that E2 would have after applying the lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions.

所以我们试图从类型 std::integral_constant<int, 1> 形成一个隐式转换序列输入 std::integral_constant<int, 2> .那是不可行的。反向的隐式转换序列也不可行。这些类型根本无法相互转换。

所以我们继续:

If no conversion sequence can be formed, the operands are left unchanged and further checking is performed as described below. [...]

If the second and third operands are glvalues of the same value category and have the same type, [...]

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, overload resolution is used to determine the conversions (if any) to be applied to the operands (13.3.1.2, 13.6). If the overload resolution fails, the program is ill-formed.

好的,我们可以执行什么重载决议?来自 [over.match.oper]:

If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator.

在 [over.built] 中将内置函数指定为:

For every pair of promoted arithmetic types L and R, there exist candidate operator functions of the form

LR operator?:(bool, L , R );

where LR is the result of the usual arithmetic conversions between types L and R.

其中一个内置函数是 int operator?:(bool, int, int) .自 std::integral_constant<int, V>确实有一个 operator int() ,这是两个参数的可行转换。

我们在 [expr.cond] 中继续:

Otherwise, the conversions thus determined are applied, and the converted operands are used in place of the original operands for the remainder of this section.

Lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the second and third operands. After those conversions, one of the following shall hold:
— The second and third operands have the same type; the result is of that type and the result object is initialized using the selected operand.

此时,第二个和第三个操作数确实具有相同的类型:int .所以结果对象被初始化为 int , 并且表达式是合式的。

关于c++ - 三元运算符中的 integral_constants,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42421458/

相关文章:

c++ - QT c++内部变量移交

python - 导入 python 包时找不到 Armadillo 库(OS X,Python 2.7)

C++ 错误处理模式

c++ - 枚举类型布局是否与其基础类型兼容?

c++ - 尝试通过 using-declaration 定义命名空间成员

c++ - 在C++中从另一个数组初始化结构内的数组

c++ - 如何将字符变量存入二维字符变量

c - 使用类型双关将对象分解为单词

java - 允许整数数字之间使用下划线的理由是什么?

c++ - 在不同源文件中声明的相同名称类没有编译器/链接器错误