在列表初始化中缩小转换为bool - 奇怪的行为

时间:2014-12-16 14:51:51

标签: c++ c++11 standards-compliance narrowing list-initialization

考虑这段C ++ 11代码:

#include <iostream>

struct X
{
    X(bool arg) { std::cout << arg << '\n'; }
};

int main() 
{
    double d = 7.0;
    X x{d};
}

x的初始化过程中,从double变为bool的缩小转换。根据我对标准的理解,这是错误的代码,我们应该看到一些诊断。

Visual C ++ 2013发出错误:

error C2398: Element '1': conversion from 'double' to 'bool' requires a narrowing conversion

但是,Clang 3.5.0和GCC 4.9.1都使用以下选项

-Wall -Wextra -std=c++11 -pedantic 

使用无错误且无警告编译此代码。运行该程序会输出1(毫不奇怪)。


现在,让我们深入到陌生的领域。

X(bool arg)更改为X(int arg),突然之间,我们从Clang那里得到了错误

error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]

和GCC的警告

warning: narrowing conversion of 'd' from 'double' to 'int' inside { } [-Wnarrowing]

这看起来更像我期待的。


现在,保留bool构造函数参数(即,还原为X(bool arg)),并将double d = 7.0;更改为int d = 7;。同样,来自Clang的一个缩小的错误,但GCC根本没有发出任何诊断并编译代码。

如果我们将常量直接传递给构造函数,我们可以得到更多的行为变体,有些奇怪,有些是预期的,但我不会在这里列出它们 - 这个问题太长了,因为它是


我说这是少数情况下VC ++是正确的,而Clang和GCC在标准一致性方面是错误的,但是,考虑到这些编译器的相应跟踪记录,我是对此仍然非常犹豫。

专家们的想法是什么?


标准参考(C ++ 11,ISO / IEC 14882-2011最终标准文件中的引用):

在8.5.4 [dcl.init.list]第3段中,我们有:

  

- 否则,如果T是类类型,则考虑构造函数。列举了适用的构造函数   通过重载决策选择最好的一个(13.3,13.3.1.7)。如果缩小转换(见   如果需要转换任何参数,程序就是格式错误。

在同一部分的第7段中,我们有:

  

缩小转换是隐式转换    - 从浮点类型到整数类型,或
   - 从long double到double或float,或从double到float,除非source是常量   表达式和转换后的实际值在可以表示的值范围内   (即使它无法准确表示),或者    - 从整数类型或未范围的枚举类型到浮点类型,除了源   是一个常量表达式,转换后的实际值将适合目标类型   转换回原始类型时产生原始值,或
   - 从整数类型或未范围的枚举类型到不能代表所有的整数类型   原始类型的值,除非源是常量表达式,后面是实际值   转换将适合目标类型,并在转换回时生成原始值   原型。
  [注意:如上所述,list-initializations.-end中的顶层不允许进行此类转换   注意]

在3.9.1 [basic.fundamental]第7段中,我们有:

  

类型bool,char,char16_t,char32_t,wchar_t以及有符号和无符号整数类型是统一的   称为整数类型。整数类型的同义词是整数类型。

(我现阶段开始质疑一切......)

1 个答案:

答案 0 :(得分:16)

如果我们尝试以下操作,这看起来就像一个错误:

bool b {3} ;

gccclang都会发出诊断信息,例如gcc说:

  

警告:缩小{3'从'int'到'bool'的转换{} [-Wnarrowing]

draft C++11 standard部分8.5.4 列表初始化 7 涵盖了这一点,其中包含:

  

缩小转化是隐式转化

     

[...]

     
      
  • 从整数类型或未范围的枚举类型到整数类型   除了之外,它不能代表原始类型的所有值   其中source是常量表达式,后面是实际值   转换将适合目标类型并将生成原始   转换回原始类型时的值。
  •   

这是涵盖您的示例和以下更简单示例的相同段落:

bool a {3.0} ;

这将由上文引用的7段中的子弹涵盖:

  
      
  • 从浮点类型到整数类型,或
  •   

3段开始,这是一个不完整的要求诊断:

  

对象或类型T的引用的列表初始化定义如下:

     

[...]

     
      
  • 否则,如果初始化列表具有单个元素,则从该对象或引用初始化该对象或引用   元件;如果需要缩小转换(见下文)将元素转换为T,则程序为   不良形成。
  •   

哪个gcc没有产生诊断但clang确实提供了以下警告,但不是我们应该看到的缩小转化警告:

  

警告:从'double'到'bool'的隐式转换将值从3更改为true [-Wliteral-conversion]

注意,3.9.1 [basic.fundamental] 部分说:

  

类型 bool ,char,char16_t,char32_t,wchar_t以及有符号和无符号整数类型是统一的   称为整数类型 .48 整数类型的同义词是整数类型

您应该使用clanggcc提交错误报告。

Jonathan Wakely指出,EDG编译器为OP代码提供了一个缩小的误差,这表明这确实应该产生诊断。

更新

我提交了gccclang错误报告。

clang bug report has been updated as fixed

  

已在r229792中修复。

gcc bug report has been updated as fixed

  

固定。

live example seems to confirm this