了解非重载按位运算符的转换顺序,算术转换和整数提升

时间:2015-12-08 03:53:31

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

当编译器遇到非重载运算符以及运算的转换时,我想准确理解发生了什么。例如,让我们使用按位运算符,例如&。标准说:

  

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

然后,如果我正在寻找通常的算术转换,我得到了:

  

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

     
      
  • 如果任一操作数是作用域枚举类型(7.2),则不执行任何转换;如果是另一个   操作数的类型不同,表达式格式不正确。
  •   
  • 如果任一操作数的类型为long double,则另一个操作数应转换为long double。
  •   
  • 否则,如果任一操作数为double,则另一个操作数应转换为double。
  •   
  • 否则,如果任一操作数为float,则另一操作数应转换为float。
  •   
  • 否则,应对两个操作数执行整体促销。然后,以下规则应适用于提升的操作数:      
        
    • 如果两个操作数具有相同的类型,则无需进一步转换。
    •   
    • 否则,如果两个操作数都有有符号整数类型或两者都有无符号整数类型,则具有较小整数转换等级类型的操作数应转换为具有更高等级的操作数类型。
    •   
    • 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则带有符号整数类型的操作数应转换为具有无符号整数类型的操作数的类型。
    •   
    • 否则,如果带有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数应转换为带有符号整数的操作数的类型类型。
    •   
    • 否则,两个操作数都应转换为与带有符号整数类型的操作数类型对应的无符号整数类型
    •   
  •   

现在,如果我们寻求整数提升:

  

[conv.prom]

     
      
  • 如果int可以表示源类型的所有值,则整数转换等级小于int的整数转换等级的bool,char16_t,char32_t或wchar_t之类的整数类型的prvalue可以转换为int类型的prvalue ;否则,源prvalue可以转换为unsigned int类型的prvalue。
  •   
  • char16_t,char32_t或wchar_t(3.9.1)类型的prvalue可以转换为以下第一种类型的prvalue,它们可以表示其基础类型的所有值:int,unsigned int,long int, unsigned long int,long long int或unsigned long long int。如果该列表中的任何类型都不能表示其基础类型的所有值,则可以将char16_t,char32_t或wchar_t类型的prvalue转换为其基础类型的prvalue。
  •   
  • 其基础类型未修复的未作用域枚举类型的prvalue可以转换为以下第一种类型的prvalue,它们可以表示枚举的所有值:int,unsigned int,long int,unsigned long int ,long long int或unsigned long long int。如果该列表中的任何类型都不能表示枚举的所有值,则可以将未作用域的枚举类型的prvalue转换为扩展的prvalue。   具有最小整数转换等级的整数类型,其大于长long的等级,其中可以表示枚举的所有值。如果有两种这样的扩展类型,则选择签名的类型。
  •   
  • 其基础类型固定的未作用域枚举类型的prvalue可以转换为其基础类型的prvalue。此外,如果可以对其基础类型应用整数提升,则固定基础类型的无范围枚举类型的prvalue也可以转换为提升的基础类型的prvalue。
  •   
  • 如果int可以表示位字段的所有值,则可以将整数位字段的prvalue转换为int类型的prvalue;否则,如果unsigned int可以表示位字段的所有值,则可以将其转换为unsigned int。如果位字段较大,则不适用整数提升。如果位字段具有枚举类型,则将其视为该类型的任何其他值以用于促销目的。
  •   
  • bool类型的prvalue可以转换为int类型的prvalue,false变为0,true变为1。
  •   
  • 这些转化称为整体促销。
  •   

但如果我们这样做:

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

它会起作用,虽然我不知道标准中指定的位置。我想确切地说,在订单中完成的所有转换检查。我认为首先,编译器检查运算符&amp;具有完全类型的过载。然后我不知道编译器做了什么其他测试。并且可能仅在此之后它使用通常的算术转换然后进行积分促销。

那么转换器测试和步骤是编译器在做什么以及遇到T1 & T2时的顺序是什么? (欢迎提取标准)。

1 个答案:

答案 0 :(得分:1)

当编译器看到这个时:

int z = x & y;

我们会发现operator &没有具体的std::integral_constant<>。但是,我会看到explicitoperator value_type()存在非x y。由于value_typeint,因此可以直接匹配最常见的operator &

不需要或不执行算术转换或整体升级。

[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)。