Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
311 views
in Technique[技术] by (71.8m points)

c++ - Why doesn't narrowing conversion used with curly-brace-delimited initializer cause an error?

I learnt about curly-brace-delimited initializer in The C++ Programming Language, 4th ed. > Chapter 2: A Tour of C++: The Basics.

I am quoting from the book below.

The = form is traditional and dates back to C, but if in doubt, use the general {} -list form (§6.3.5.2). If nothing else, it saves you from conversions that lose information (narrowing conversions; §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)

However, I am unable to reproduce these results.

I have the following code.

#include <iostream>

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

    std::cout << i1 << "
";
    std::cout << i2 << "
";
    std::cout << i3 << "
";
}

When I compile and run it, I don't get any error. I get a warning about std=c++11 but no error.

$ 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

Further, the warning is only for the second assignment but there is no warning for the third assignment. This seems to indicate that the = is not really redundant as mentioned in the book. If = were redundant, either both the second and third assignments would have produced warnings or both would not have produced warnings. Then I compile them with the -std=c++11 flag.

$ 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

Still no error. Only warnings. Although in this case the second and third assignments behave identically with respect to generating warnings.

So my question is: Although the book mentions that the second and third assignments are errors, why doesn't this code fail to compile?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is ill-formed and there should be diagnostic, however it can either be a warning(which you received) or an error. gcc made this a warning for several versions due to porting issue from C++03:

The standard only requires that "a conforming implementation shall issue at least one diagnostic message" so compiling the program with a warning is allowed. As Andrew said, -Werror=narrowing allows you to make it an error if you want.

G++ 4.6 gave an error but it was changed to a warning intentionally for 4.7 because many people (myself included) found that narrowing conversions where one of the most commonly encountered problems when trying to compile large C++03 codebases as C++11. Previously well-formed code such as char c[] = { i, 0 }; (where i will only ever be within the range of char) caused errors and had to be changed to char c[] = { (char)i, 0 }

but now recent versions of gcc and clang make this an error, see it live for gcc.

For reference the draft C++11 standard section 8.5.4 [dcl.init.list] says:

Otherwise, if the initializer list has a single element, the object or reference is initialized from that element; if a narrowing conversion (see below) is required to convert the element to T, the program is ill-formed. [ Example:

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

—end example ]

and:

A narrowing conversion is an implicit conversion

  • from a floating-point type to an integer type, or

[...]

[ Note: As indicated above, such conversions are not allowed at the top level in list-initializations.—end note ] [ Example:

[...]

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

[...]

So a floating point to integer conversion is a narrowing conversion and is ill-formed.

and section 1.4 Implementation compliance [intro.compliance] says:

Although this International Standard states only requirements on C++ implementations, those requirements are often easier to understand if they are phrased as requirements on programs, parts of programs, or execution of programs. Such requirements have the following meaning:

[...]

  • If a program contains a violation of any diagnosable rule or an occurrence of a construct described in this Standard as “conditionally-supported” when the implementation does not support that construct, a conforming implementation shall issue at least one diagnostic message.

[...]

Tells us that only a diagnostic is required.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...