为什么缩小使用花括号分隔初始值设定项的转换会导致错误?

Lon*_*ner 13 c++ narrowing c++11

我在"C++编程语言"第4版中学习了大括号分隔初始化器.>第2章:C++之旅:基础知识.

我引用下面的书.

=表格是传统的并且可以追溯到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)
Run Code Online (Sandbox Code Playgroud)

但是,我无法重现这些结果.

我有以下代码.

#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";
}
Run Code Online (Sandbox Code Playgroud)

当我编译并运行它时,我没有得到任何错误.我收到警告,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
Run Code Online (Sandbox Code Playgroud)

此外,警告仅适用于第二次分配,但第三次分配没有警告.这似乎表明,=书中提到的并不是真正多余的.如果=是多余的,则第二次和第三次分配都会产生警告,或者两者都不会产生警告.然后我用-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
Run Code Online (Sandbox Code Playgroud)

仍然没有错误.只有警告.虽然在这种情况下,第二次和第三次分配在产生警告方面的行为相同.

所以我的问题是:尽管本书提到第二和第三个赋值都是错误,为什么这个代码不能编译?

Sha*_*our 13

这是不正确的,应该有诊断,但它可能是一个警告(你收到)或错误.由于C++ 03的移植问题,gcc对几个版本发出警告:

该标准仅要求"符合要求的实现应至少发出一条诊断消息",因此允许编写程序并发出警告.正如Andrew所说,-Werror = narrowing允许你在需要时使其成为错误.

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

但现在gcc和clang的最新版本使这个错误,看到它为gcc现场直播.

作为参考,草案C++ 11标准部分8.5.4 [dcl.init.list]说:

否则,如果初始化列表具有单个元素,则从该元素初始化对象或引用; 如果需要缩小转换(见下文)将元素转换为T,则程序格式不正确.[例如:

int x1 {2}; // OK
int x2 {2.0}; // error: narrowing
Run Code Online (Sandbox Code Playgroud)

- 末端的例子]

和:

缩小转换是隐式转换

  • 从浮点类型到整数类型,或

[...]

[注意:如上所述,列表初始化中顶层不允许进行此类转换.-结尾注释] [示例:

[...]

int ii = {2.0}; // error: narrows
Run Code Online (Sandbox Code Playgroud)

[...]

因此,浮点到整数转换是一种缩小的转换并且是不正确的.

和部分1.4实施合规性[intro.compliance]说:

虽然本国际标准仅规定了对C++实现的要求,但如果将这些要求表达为对程序,程序部分或程序执行的要求,则这些要求通常更容易理解.这些要求具有以下含义:

[...]

  • 如果程序包含违反任何可诊断规则或本标准中描述的构造的发生,如果实现不支持该构造,则符合条件的实现应发出至少一条诊断消息.

[...]

告诉我们只需要诊断.


AnT*_*AnT 8

C++语言不区分"警告"和"错误".C++只有诊断消息.您收到的警告是诊断消息.语言规范不要求编译器在遇到错误(也就是格式错误的)代码时停止编译.所有编译器必须做的是发出诊断消息,然后如果他们愿意,他们可以继续编译.

这意味着在一般情况下,您有责任告知警告"警告",这些警告实际上表示真正的错误,特别是对于像GCC这样的许可编译器.

这也意味着实际的真实行为是编译器设置的问题.如果可能的话,请求您的编译器在这方面更具限制性.在GCC中,您可以尝试-pedantic-errors切换以实现此目的.

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