24

考虑这段 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 

编译这段代码没有错误和警告。运行程序会输出 a 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,除非源是常量表达式并且转换后的实际值是在可以表示的值范围内(即使不能精确表示),或者
——从整数类型或无作用域枚举类型到浮点类型,除非源是常量表达式和转换后的实际值将适合目标类型并在转换回原始类型时生成原始值,或者
— 从整数类型或无作用域枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式并且转换后的实际值将适合目标类型并生成原始值当转换回原始类型时。
[注意:如上所述,列表初始化中的顶级不允许此类转换。-结束注释]

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

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

(在这个阶段我开始质疑一切......)

4

1 回答 1

16

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

bool b {3} ;

两者gccclang发出诊断,例如gcc说:

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

这在C++11 标准草案的8.5.4 List-initialization7段中有所介绍,其中说:

缩小转换是隐式转换

[...]

  • 从整数类型或无作用域枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式并且转换后的实际值将适合目标类型并在以下情况下生成原始值转换回原来的类型。

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

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 编译器为 OPs 代码提供了一个缩小错误,这强烈表明这确实应该产生诊断。

更新

我提交了一份gccclang错误报告。

clang 错误报告已更新为已修复:

已在 r229792 中修复。

gcc 错误报告已更新为已修复:

固定的。

一个活生生的例子似乎证实了这一点

于 2014-12-16T15:52:52.727 回答