【问题标题】:Understanding the order of conversions, arithmetic conversions, and integer promotions for non-overloaded bitwise operators了解非重载位运算符的转换顺序、算术转换和整数提升
【发布时间】:2016-03-12 21:22:34
【问题描述】:

我想确切地了解发生了什么,当编译器遇到非重载运算符时以及进行了哪些转换。例如,让我们以位运算符为例,例如&。标准说:

[expr.bit.and] 执行通常的算术转换;结果是操作数的按位与函数。该运算符仅适用于整数或无范围枚举操作数。

然后,如果我正在搜索通常的算术转换,我得到:

[expr] 许多期望算术或枚举类型的操作数的二元运算符会导致转换并以类似的方式产生结果类型。目的是产生一个通用类型,这也是结果的类型。 这种模式称为通常的算术转换,定义如下:

  • 如果任一操作数属于范围枚举类型 (7.2),则不执行任何转换;如果另一个 操作数的类型不同,表达式格式不正确。
  • 如果任一操作数为 long double 类型,则另一个应转换为 long double。
  • 否则,如果任一操作数为双精度,则另一个应转换为双精度。
  • 否则,如果任一操作数为浮点数,则另一个应转换为浮点数。
  • 否则,应对两个操作数执行积分提升。然后将以下规则应用于提升的操作数:
    • 如果两个操作数的类型相同,则无需进一步转换。
    • 否则,如果两个操作数都是有符号整数类型或都具有无符号整数类型,则整数转换等级较小的操作数应转换为等级较高的操作数类型。
    • 否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数的类型。
    • 否则,如果带符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的所有值,则将无符号整数类型的操作数转换为带符号整数类型的操作数的类型输入。
    • 否则,两个操作数都应转换为与带符号整数类型的操作数类型对应的无符号整数类型

现在如果我们看一下整数提升:

[conv.prom]

  • 如果 int 可以表示源类型的所有值,则可以将除 bool、char16_t、char32_t 或 wchar_t 的整数转换等级小于 int 等级的整数类型的纯右值转换为 int 类型的纯右值;否则,可以将源纯右值转换为 unsigned int 类型的纯右值。
  • char16_t、char32_t 或 wchar_t (3.9.1) 类型的纯右值可以转换为以下第一种类型的纯右值,该类型可以表示其基础类型的所有值:int、unsigned int、long int、 unsigned long int、long long int 或 unsigned long long int。如果该列表中没有任何类型可以表示其基础类型的所有值,则可以将 char16_t、char32_t 或 wchar_t 类型的纯右值转换为其基础类型的纯右值。
  • 其基础类型不固定的无作用域枚举类型的纯右值可以转换为以下第一种类型的纯右值,该类型可以表示枚举的所有值:int、unsigned int、long int、unsigned long int 、long long int 或 unsigned long long int。如果该列表中的任何类型都不能表示枚举的所有值,则可以将无作用域枚举类型的纯右值转换为扩展的纯右值 具有最低整数转换等级的整数类型大于可以表示枚举的所有值的 long long 等级。如果有两种这样的扩展类型,则选择带符号的。
  • 其基础类型固定的无范围枚举类型的纯右值可以转换为其基础类型的纯右值。此外,如果可以将整型提升应用于其基础类型,则其基础类型固定的无作用域枚举类型的纯右值也可以转换为提升的基础类型的纯右值。
  • 如果 int 可以表示位域的所有值,则整数位域的纯右值可以转换为 int 类型的纯右值;否则,如果 unsigned int 可以表示位域的所有值,则可以将其转换为 unsigned int。如果位域更大,则不会对其应用积分提升。如果位字段具有枚举类型,则将其视为该类型的任何其他值以用于提升目的。
  • bool 类型的纯右值可以转换为 int 类型的纯右值,false 变为 0,true 变为 1。
  • 这些转化称为积分促销。

但如果我们这样做:

std::integral_constant<int, 2> x;
std::integral_constant<int, 3> y;
int z = x & y;

它会起作用,虽然我没有看到它在标准中的指定位置。我想确切地说,按顺序完成的所有转换检查。我认为首先,编译器检查 operator& 是否具有完全采用类型的重载。然后我不知道编译器做了哪些其他测试。并且可能只有在那之后它才使用通常的算术转换,然后是积分提升。

那么编译器在执行哪些转换测试和步骤,遇到T1 &amp; T2 时的顺序是什么? (欢迎从标准中摘录)。

【问题讨论】:

    标签: c++11 integer type-conversion standards integer-promotion


    【解决方案1】:

    当编译器看到这个时:

    int z = x & y;
    

    它会看到std::integral_constant&lt;&gt; 没有特定的operator &amp;。然而,它会看到xy 有一个非explicit operator value_type()。由于value_typeint,因此可以直接匹配最常见的operator &amp;

    不需要或执行算术转换或整数提升。

    [conv] (2.1) 说:

    用作运算符的操作数时。运算符对其操作数的要求决定了目标类型。

    [over.match] 说:

    这些上下文中的每一个都以自己独特的方式定义了一组候选函数和参数列表。 但是,一旦确定了候选函数和参数列表,就可以选择最佳函数 在所有情况下都是一样的:

    • (2.8) — 首先,候选函数的子集(具有适当数量的参数并满足 某些其他条件)被选择以形成一组可行的功能(13.3.2)。
    • (2.9) — 然后根据所需的隐式转换序列 (13.3.3.1) 选择最佳可行函数 将每个参数与每个可行函数的相应参数相匹配。

    [class.conv] 说:

    类对象的类型转换可以由构造函数和转换函数指定。这些 转换称为用户定义的转换,用于隐式类型转换(第 4 条),例如 初始化 (8.5) 和显式类型转换 (5.4, 5.2.9)。

    【讨论】:

    • 它在标准中的什么位置? (我试图从标准中理解它)
    • @Vincent:我添加了一些我认为相关的标准引用。
    • 这会通过 [over.match.oper],对 [over.built]/17 中指定的一组内置候选者进行重载解决。
    猜你喜欢
    • 1970-01-01
    • 2016-04-01
    • 1970-01-01
    • 2021-12-31
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多