考虑这段C++11代码:
#include <iostream>
struct X
{
X(bool arg) { std::cout << arg << 'n'; }
};
int main()
{
double d = 7.0;
X x{d};
}
在 x
的初始化中,有一个从双精度到布尔值的缩小转换。根据我对标准的理解,这是格式错误的代码,我们应该看到一些诊断。
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]
以及海湾合作委员会的警告
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段中,我们有:
缩小转换是隐式转换
— 从浮点类型到整数类型,或
— 从长双精度到双精度或浮点数,或从双精度到浮点数,除非源是常数 表达式和转换后的实际值在可以表示的值范围内 (即使不能准确表示(,或
— 从整数类型或无作用域枚举类型到浮点类型,源除外 是一个常量表达式,转换后的实际值将适合目标类型,并且 转换回原始类型时生成原始值,或
— 从整数类型或无作用域枚举类型到不能表示所有 原始类型的值,除非源是常量表达式且实际值在之后 转换将适合目标类型,并在转换回 原始类型。
[ 注意:如上所述,在列表初始化的顶层不允许进行此类转换。 注]
在 3.9.1 [基本.基本] 第 7 段中,我们有:
布尔、字符、char16_t、char32_t、wchar_t 类型以及有符号和无符号整数类型是集合的 称为整型.48 整型的同义词是整型。
(我在这个阶段开始质疑一切...
如果我们尝试以下操作,这看起来只是一个错误:
bool b {3} ;
gcc
和clang
都会发出诊断,例如gcc
说:
警告:在 { } 内将"3"从"int"缩小到"bool"的转换范围 [-缩小]
这在C++11标准草案第8.5.4
节的清单初始化第7段中有所涉及,该段规定:
缩小转换是隐式转换
[...]
从整数类型
- 或无作用域枚举类型到整数类型 不能表示原始类型的所有值,除了 其中源是常量表达式,之后的实际值 转换将适合目标类型,并将生成原始 转换回原始类型时的值。
这是涵盖您的示例和以下更简单示例的同一段落:
bool a {3.0} ;
上文引述的第7
段中的此项目符号将涵盖:
- 从浮点类型到整数类型,或
从第 3
段来看,这是格式不正确的,需要诊断:
类型 T 的对象或引用的列表初始化定义如下:
[...]
- 否则,如果初始值设定项列表具有单个元素,则从该元素初始化对象或引用 元素;如果需要缩小转换(见下文(才能将元素转换为 T,则程序是 格式不正确。
gcc
不会产生诊断信息,但clang
确实提供了以下警告,尽管不是我们应该看到的缩小转换范围警告:
警告:从"双精度"到"布尔"的隐式转换会将值从 3 更改为 true [-文字转换]
注意,[basic.basic] 第 3.9.1
节说:
布尔、字符、char16_t、char32_t、wchar_t 类型以及有符号和无符号整数类型是集合的 称为整型.48 整型的同义词是整型。
您应该同时向clang和gcc提交错误报告。
Jonathan Wakely 指出,EDG 编译器为 OPs 代码提供了缩小错误,这强烈表明这确实应该产生诊断。
更新
我提交了一份 gcc 和 clang 错误报告。
clang 错误报告已更新为已修复:
在 r229792 中修复。
gcc 错误报告已更新为已修复:
固定。
一个活生生的例子似乎证实了这一点。