Ros*_*lav 11 c++ language-lawyer
MSVC和clang/gcc不同意是否可以在三元运算符中使用两个不同的积分常数(因此它们是否具有a common_type):
#include <utility>
int main()
{
return false
? std::integral_constant<int, 1>()
: std::integral_constant<int, 2>();
}
Run Code Online (Sandbox Code Playgroud)
上面的代码段在clang和gcc中编译得很好,但在MSVC中却没有.根据标准,正确的行为是什么?如果它是clang/gcc行为,那么用于推断这两种不同类型的常见类型的转换序列是什么?
tldr; 代码格式正确.条件表达式将具有类型int和值2.这是一个MSVC错误.
从[expr.cond]:
否则,如果第二个和第三个操作数具有不同的类型并且具有(可能是cv限定的)类类型或[...],则尝试从每个操作数形成隐式转换序列(13.3.3.1)到另一种的类型.[...]尝试以从形成的操作数表达的隐式转换序列
E1类型的T1相关的类型的目标类型T2的操作数的表达式E2如下:[...]
-如果E2是一个左值,[.. .]
- 如果E2是x值,[...]
- 如果E2是prvalue或者如果上面的转换序列都不能形成且至少有一个操作数具有(可能是cv-qualified)类类型:
- if T1和T2是相同的类类型(忽略cv-qualification),或者一个是另一个的基类,T2至少与T1一样是cv限定的,目标类型是T2,
否则,目标类型是应用左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换后E2的类型.
所以我们试图从一个类型std::integral_constant<int, 1>到另一个类型形成一个隐式转换序列std::integral_constant<int, 2>.这不可行.反向的隐式转换序列也不可行.这些类型根本不可互换.
所以我们继续:
如果不能形成转换序列,则操作数保持不变,并且如下所述执行进一步检查.[...]
如果第二个和第三个操作数是相同值类别的glvalues并且具有相同的类型,[...]
否则,结果是prvalue.如果第二个和第三个操作数不具有相同的类型,并且具有(可能是cv限定的)类类型,则使用重载决策来确定要应用于操作数的转换(如果有)(13.3.1.2,13.6) .如果重载决策失败,则程序格式错误.
好的,我们可以执行什么重载决策?来自[over.match.oper]:
如果任一操作数具有类或枚举类型,则可以声明用户定义的操作符函数来实现此运算符,或者可能需要用户定义的转换将操作数转换为适合于构造函数的类型.在运营商.
内核在[over.built]中指定为:
对于每对提升的算术类型L和R,存在该形式的候选运算符函数
Run Code Online (Sandbox Code Playgroud)LR operator?:(bool, L , R );其中LR是类型L和R之间通常的算术转换的结果.
其中一个内置的将是int operator?:(bool, int, int).既然std::integral_constant<int, V>有operator int(),那么这是两个参数的可行转换.
我们继续[expr.cond]:
否则,应用如此确定的转换,并使用转换的操作数代替本节其余部分的原始操作数.
在第二个和第三个操作数上执行左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)标准转换.在这些转换之后,以下之一应该成立:
- 第二和第三个操作数具有相同的类型; 结果是该类型,并使用所选操作数初始化结果对象.
在这一点上,第二个和第三个操作数都具有相同的类型:int.因此,结果对象初始化为a int,表达式格式正确.
[expr.cond]的相关段落是6:
否则,结果是prvalue.如果第二个和第三个操作数不具有相同的类型,并且具有(可能是cv限定的)类类型,则使用重载决策来确定要应用于操作数的转换(如果有)(13.3.1.2,13.6) .如果重载决策失败,则程序格式错误.否则,应用如此确定的转换,并使用转换的操作数代替本节其余部分的原始操作数.
integral_constant<int>有一个转换运算符int,所以这可以工作.接下来通过13.3.1.2,我们看到,在第3.2段中,所有?:采用整数和浮点参数的内置运算符都是候选者.
现在给出我们的三个参数,对所有这些执行重载解析.根据[over.ics.rank] /3.3,我们通过比较int(integral_constant<int>转换运算符的返回类型)到内置运算符参数类型的标准转换序列来打破中断.
但是,看看表13就足够了; 对浮点类型的转换具有转换排名,并且由于int是升级类型,转换为任何整数类型但是int(这是标识转换)是具有转换排名的积分转换.因此,最明确的可行候选者是明确的operator?:(bool, int, int).也就是说,MSVC是错误的.
| 归档时间: |
|
| 查看次数: |
199 次 |
| 最近记录: |