考虑这段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以及有符号和无符号整数类型是统一的 称为整数类型。整数类型的同义词是整数类型。
(我现阶段开始质疑一切......)
答案 0 :(得分:16)
如果我们尝试以下操作,这看起来就像一个错误:
bool b {3} ;
gcc
和clang
都会发出诊断信息,例如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 整数类型的同义词是整数类型。
Jonathan Wakely指出,EDG编译器为OP代码提供了一个缩小的误差,这表明这确实应该产生诊断。
更新
clang bug report has been updated as fixed:
已在r229792中修复。
gcc bug report has been updated as fixed:
固定。