我在The C ++ Programming Language,4th ed中学习了花括号分隔的初始化器。 >第2章:C ++之旅:基础知识。
我引用了下面这本书。
= form是传统的,可以追溯到C,但如果有疑问,请使用通用{} -list表单(第6.3.5.2节)。 如果不出意外,它可以帮助您避免丢失信息的转换(缩小转换次数;§10.5):
int i1 = 7.2; // i1 becomes 7 int i2 {7.2}; // error : floating-point to integer conversion int i3 = {7.2}; // error : floating-point to integer conversion (the = is redundant)
但是,我无法重现这些结果。
我有以下代码。
#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++ init.cpp
init.cpp: In function ‘int main()’:
init.cpp:6:12: warning: extended initializer lists only available with -std=c++11 or -std=gnu++11
int i2 {7.2};
^
$ ./a.out
7
7
7
此外,警告仅适用于第二次分配,但第三次分配没有警告。这似乎表明=
并不像书中提到的那样多余。如果=
是多余的,则第二次和第三次分配都会产生警告,或者两者都不会产生警告。
然后我用-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
仍然没有错误。只有警告。虽然在这种情况下,第二次和第三次分配在产生警告方面的行为相同。
所以我的问题是:尽管本书提到第二和第三个作业都是错误,为什么这个代码不能编译?
答案 0 :(得分:13)
这是不正确的,应该有诊断,但它可以是警告(你收到)或错误。 gcc made this a warning for several versions due to porting issue from C++03:
该标准仅要求符合条件的实施方案应至少发出一条诊断信息&#34;所以允许用警告编译程序。正如Andrew所说,-Werror = narrowing允许你在你想要的时候把它变成错误。
G ++ 4.6给出了一个错误,但是因为很多人(包括我自己)发现在尝试编译大型C ++ 03代码库时最常遇到的问题之一变为C + +11。以前格式良好的代码,例如char c [] = {i,0}; (其中我只会在char范围内)导致错误并且必须更改为char c [] = {(char)i,0}
但是现在gcc和clang的最新版本使这个错误see it live for gcc。
作为参考,draft C++11 standard部分8.5.4
[dcl.init.list] 表示:
否则,如果初始化列表具有单个元素,则对象或 引用从该元素初始化;如果缩小转换 (见下文)需要将元素转换为T,程序是 病态的。 [例如:
int x1 {2}; // OK int x2 {2.0}; // error: narrowing
-end example]
和
缩小转化是隐式转化
- 从浮点类型到整数类型,或
[...]
[注意:如上所述,list-initializations.-end中的顶层不允许进行此类转换 注意] [例子:
[...]
int ii = {2.0}; // error: narrows
[...]
因此,浮点到整数转换是一种缩小的转换,并且格式不正确。
和部分1.4
实施合规性[intro.compliance]说:
虽然本国际标准仅规定了对C ++实现的要求,但这些要求 如果它们被表达为对程序,程序部分或者程序的要求,则通常更容易理解 执行程序。这些要求具有以下含义:
[...]
- 如果某个程序包含违反任何可诊断规则或发生的描述 当实现不支持该构造时,此标准为“有条件支持”, 符合要求的实施应至少发布一条诊断信息。
[...]
告诉我们只需要诊断。
答案 1 :(得分:8)
C ++语言不区分“警告”和“错误”。 C ++只有诊断消息。您收到的警告是诊断消息。语言规范不要求编译器在遇到错误(也就是格式错误的)代码时停止编译。所有编译器必须做的是发出诊断消息,然后如果他们愿意,他们可以继续编译。
这意味着在一般情况下,您有责任告知警告“警告”,这些警告实际上表示真正的错误,特别是对于像GCC这样的许可编译器。
这也意味着实际的真实行为是编译器设置的问题。如果可能的话,请求您的编译器在这方面更具限制性。在GCC中,您可以尝试-pedantic-errors
为此目的切换。
P.S。在我使用GCC的实验中,-std=c++11
足以让它为您的代码生成错误。如果您收到警告,则可能是编译器版本问题。