为什么';与大括号分隔的初始值设定项一起使用的t缩小转换是否会导致错误? 我在C++编程语言中学习了卷曲括号分隔的初始化器,第四版。第2章:C++教程:基本知识。

为什么';与大括号分隔的初始值设定项一起使用的t缩小转换是否会导致错误? 我在C++编程语言中学习了卷曲括号分隔的初始化器,第四版。第2章:C++教程:基本知识。,c++,c++11,narrowing,C++,C++11,Narrowing,我引用了下面这本书中的话 =形式是传统的,可以追溯到C,但如果有疑问,请使用通用{}-列表形式(§6.3.5.2)。 如果没有其他内容,则可以避免丢失信息的转换(缩小转换范围;§10.5): 然而,我无法重现这些结果 我有以下代码 #include <iostream> int main() { int i1 = 7.2; int i2 {7.2}; int i3 = {7.2}; std::cout << i1 << "\

我引用了下面这本书中的话

=形式是传统的,可以追溯到C,但如果有疑问,请使用通用{}-列表形式(§6.3.5.2)。 如果没有其他内容,则可以避免丢失信息的转换(缩小转换范围;§10.5):

然而,我无法重现这些结果

我有以下代码

#include <iostream>

int main()
{
    int i1 = 7.2;
    int i2 {7.2};
    int i3 = {7.2};

    std::cout << i1 << "\n";
    std::cout << i2 << "\n";
    std::cout << i3 << "\n";
}
此外,警告仅适用于第二次分配,而不适用于第三次分配。这似乎表明
=
并不像书中提到的那样是多余的。如果
=
是冗余的,则第二次和第三次分配都会产生警告,或者两者都不会产生警告。 然后我用
-std=c++11
标志编译它们

$ g++ -std=c++11 init.cpp 
init.cpp: In function ‘int main()’:
init.cpp:6:16: warning: narrowing conversion of ‘7.2000000000000002e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
     int i2 {7.2};
                ^
init.cpp:7:18: warning: narrowing conversion of ‘7.2000000000000002e+0’ from ‘double’ to ‘int’ inside { } [-Wnarrowing]
     int i3 = {7.2};
                  ^
$ ./a.out 
7
7
7
仍然没有错误。只有警告。尽管在这种情况下,第二个和第三个赋值在生成警告方面表现相同


所以我的问题是:尽管书中提到第二个和第三个赋值是错误,为什么这段代码没有编译失败?

C++语言没有区分“警告”和“错误”。C++只具有诊断消息。您收到的警告是诊断信息。语言规范不要求编译器在遇到错误(又称格式错误)代码时停止编译。编译器所要做的就是发出一条诊断消息,然后他们可以继续编译,如果他们愿意的话

这意味着,在一般情况下,您有责任将“只是警告”的警告与实际指示真实错误的警告区分开来,特别是对于GCC这样的许可编译器

这也意味着实际的行为是编译器设置的问题。如果可能的话,要求编译器在这方面更加严格。在GCC中,您可以为此尝试
-pedanticerrors
开关


另外,在我的GCC实验中,
-std=c++11
足以使它为您的代码生成错误。如果您收到的是警告,则可能是编译器版本的问题。

这是格式错误的,应该有诊断,但可能是警告(您收到的)或错误:

该标准仅要求“符合要求的实施应发出至少一条诊断信息”,因此允许编译带有警告的程序。正如Andrew所说,-Werror=缩小允许您在需要时将其设置为错误

G++4.6给出了一个错误,但在4.7中故意将其更改为警告,因为许多人(包括我自己)发现,在试图将大型C++03代码基编译为C++11时,最常见的问题之一是缩小转换范围。以前格式良好的代码,例如char c[]={i,0};(其中我将只在char的范围内)导致错误,必须更改为char c[]={(char)i,0}

但现在gcc和clang的最新版本使这成为一个错误

参考章节
8.5.4
[dcl.init.list]中说明:

否则,如果初始值设定项列表只有一个元素,则对象或 从该元素初始化引用;如果缩小转换 (见下文)是将元素转换为T所必需的,程序为 格式不正确。[示例:

int x1 {2}; // OK
int x2 {2.0}; // error: narrowing
-[结束示例]

以及:

缩小转换是一种隐式转换

  • 从浮点类型到整数类型,或
[……]

int ii = {2.0}; // error: narrows
[注:如上所述,在列表初始化的顶层不允许进行此类转换。-结束 注][示例:

int x1 {2}; // OK
int x2 {2.0}; // error: narrowing
[……]

int ii = {2.0}; // error: narrows
[……]

int ii = {2.0}; // error: narrows
因此,浮点到整数的转换是一种窄化转换,并且格式不正确

1.4节
实施合规性[intro.compliance]说:

虽然这个国际标准只对C++实现提出了要求,但这些要求 如果将其表述为对程序、程序部分或程序的要求,通常更容易理解 程序的执行。此类要求具有以下含义:

[……]

int ii = {2.0}; // error: narrows
  • 如果程序违反了任何可诊断规则或出现了中描述的构造 当实现不支持该构造时,此标准被视为“有条件支持”, 一致性实施应发出至少一条诊断信息
[……]

int ii = {2.0}; // error: narrows

告诉我们只有诊断是必要的。

可能与相关和相似:第一种情况下,对于<代码> I1<代码>和 I3<代码>,没有错误,因为在C++ 11中引入了关于缩小转换的规则,并且编译器已经设置为PrC++ 11模式。编译器可能也会给它一个警告。所以你的观察没有什么不寻常的。你使用的是哪个版本的g++呢?我的是“g++”(Debian 4.9.2-10)4.9.2.@Lone Learner:我在Coliru上试用过,他们的GCC是5.2.0
一致性实现应至少发出一条诊断消息
,这是我一直在寻找的。因此,我点击了
^
以获得答案。:-)