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
246 views
in Technique[技术] by (71.8m points)

c++ - g++4.9 and g++5 different behaviour when narrowing in initializing list

Consider this code:

#include <iostream>

int main()
{
    int i{10.1}; // narrowing, should not compile
    std::cout << i << std::endl;
}

According to the C++11 standard, it should not compile (narrowing in brace initialization is forbidden.)

Now, compiling with g++4.9.2 -std=c++11 only emits a warning

warning: narrowing conversion of '1.01e+1' from 'double' to 'int' inside { } [-Wnarrowing]

Removing the -std=c++11 flag results in a warning regarding the brace init, but not any narrowing:

warning: extended initializer lists only available with -std=c++11 or -std=gnu++11

On the other hand, g++5 doesn't compile it, provided you compile with g++5 -std=c++11. However, if -std=c++11 is omitted, then even g++5 happily compiles it, giving just a warning related to the brace init, not to the narrowing:

warning: extended initializer lists only available with -std=c++11 or -std=gnu++11

The above behaviour seems buggy, g++4.9 should not compile the code, and it is more than weird that g++5 compiles it if you forget to specify -std=c++11. Is this a known problem?

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

The reason that the narrowing conversion inside {} are only an error in C++11 mode is simple: it isn't an error in C++03. Now, T var{value}; is new C++11 syntax, but T var = {value}; was already valid C++03 syntax, and did allow narrowing conversions.

int i = { 10.1 }; // valid C++03, invalid C++11

It makes it easier for the GCC developers to treat narrowing conversions the same in T var{value}; and T var={value}; initialisations. This is useful because it avoids two separate code paths for the warning in the compiler.

It makes it easier for the GCC developers to accept even the T var{value}; syntax in C++03 mode, merely warning about it. Several other C++11 syntax extensions are also enabled in C++03 mode. This is useful because several C++11 syntax extensions are used in GCC's implementation of the standard library (where warnings about it are suppressed).

The reason that int i{10.1}; isn't an error in GCC 4.9 in C++11 mode, but was made an error in GCC 5, is because not treating it as an error caused valid code to be rejected. The C++ standard requires treating it as an error in SFINAE contexts, and here is a valid C++11 program that runs incorrectly because of this with GCC 4.9:

#include <stdio.h>
template <typename T> void f(double) { puts("ok"); }
template <typename T, typename = decltype(T{10.1})> void f(int) { puts("error"); }
int main() { f<int>(1); }

This is supposed to print "ok". The second overload is supposed to be discarded.

With GCC 4.9, it prints "error", because the second overload isn't discarded, and int is a better match than double.


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

...