Here is my code:
#include <vector>
int main()
{
std::vector<int> a = {1, 2.2};
}
As expected this does not compile because of the illegal narrowing conversion:
$ clang++ -std=c++11 foo.cpp
foo.cpp:5:30: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
std::vector<int> a = {1, 2.2};
^~~
Why does this compile then with only a warning?
#include <complex>
int main()
{
std::complex<int> a = {1, 2.2};
}
Here is the warning:
$ clang++ -std=c++11 foo.cpp
foo.cpp:5:31: warning: implicit conversion from 'double' to 'std::__1::complex<int>::value_type' (aka 'int') changes value from 2.2 to 2 [-Wliteral-conversion]
std::complex<int> a = {1, 2.2};
~ ^~~
1 warning generated.
I understand the notion of diagnostics and that the C++ compiler is only required to issue a diagnostic either in the form of error or warning.
But I want to be sure that I am not misunderstanding any concept here. Especially, I want to know if there is any C++ concept that I need to know why in the first case the c++11-narrowing diagnostic was issued but in the second case literal-conversion diagnostic was issued.
Two different things are happening, which as you can see result in different diagnostics:
In the first case, you're using copy-list-initialization and finding a constructor of std::vector which takes an std::initializer_lsit.
In the second case, you're using copy-list-initialization on a LiteralType, which results in aggregate initialization.
They both should prevent narrowing conversions, but it seems that clang implements the diagnostics differently.
Related
In the following snippet no warnings are produced. g++4.4.3 -Wall -pedantic
//f is
void f(int );
f(3.14);
double d = 3.14;
int i = d+2;
I have a strong recollection of this being a warning, something along the lines of "Possible loss of precision". Was it removed or is my memory playing tricks on me?
How can i turn this into a warning in g++? I find this a useful warning, or is it a bad idea?
I can't even find anything appropriate at http://gcc.gnu.org/onlinedocs/gcc-4.4.5/gcc/Warning-Options.html
$ gcc -Wconversion test.c
test.c: In function ‘main’:
test.c:3: warning: conversion to ‘int’ from ‘double’ may alter its value
Use -Wconversion option. -Wall doesn't include it.
With -Wconversion option, GCC gives these warning messages:
warning: conversion to 'int' alters 'double' constant value
warning: conversion to 'int' from 'double' may alter its value
Apart from what other answers mention it is also worth mentioning that in C++0x {} initialization doesn't narrow. So instead of getting a warning you'll get an error for example
void f(int x)
{
// code
}
int main()
{
f({3.14}); // narrowing conversion of '3.14000000000000012434497875801753252744674682617e+0' from 'double' to 'int' inside { }
}
g++ 4.4 and above support initializer list (with -std=c++0x option)
In the following snippet no warnings are produced. g++4.4.3 -Wall -pedantic
//f is
void f(int );
f(3.14);
double d = 3.14;
int i = d+2;
I have a strong recollection of this being a warning, something along the lines of "Possible loss of precision". Was it removed or is my memory playing tricks on me?
How can i turn this into a warning in g++? I find this a useful warning, or is it a bad idea?
I can't even find anything appropriate at http://gcc.gnu.org/onlinedocs/gcc-4.4.5/gcc/Warning-Options.html
$ gcc -Wconversion test.c
test.c: In function ‘main’:
test.c:3: warning: conversion to ‘int’ from ‘double’ may alter its value
Use -Wconversion option. -Wall doesn't include it.
With -Wconversion option, GCC gives these warning messages:
warning: conversion to 'int' alters 'double' constant value
warning: conversion to 'int' from 'double' may alter its value
Apart from what other answers mention it is also worth mentioning that in C++0x {} initialization doesn't narrow. So instead of getting a warning you'll get an error for example
void f(int x)
{
// code
}
int main()
{
f({3.14}); // narrowing conversion of '3.14000000000000012434497875801753252744674682617e+0' from 'double' to 'int' inside { }
}
g++ 4.4 and above support initializer list (with -std=c++0x option)
Consider the following program:
#include <array>
int main()
{
std::array<int, 1> x = { 0 }; // warning!
x = { { 0 } }; // no warning
return 0;
}
The first initialization leads to warnings on gcc 4.7.2...
main.cpp:5:22: warning: unused variable ‘x’ [-Wunused-variable]
... and clang 3.1
main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
std::array<int, 1> x = { 0 };
As far as the standard goes, there should be no difference between double or single curly braces, at least in this example.
There are two ways to deal with the warning:
Just turn it off
Fix the code, so the compiler is happy
What do you propose? IMHO, the double curly expression looks somewhat ugly. On the other hand, the warning might detect real problems in more complicated examples. Do you know an example where the warning would have helped you?
-Wmissing-braces will no longer be enabled in GCC's -Wall (for C++ mode), as of 4.8, for precisely the reason you describe. For current versions of GCC, either disable or ignore the warning, the code you have is written the way it should be.
The warning is probably meant to cover code such as
struct A { int a; int b; };
struct B { A a; int b; };
B b = {
1,
2 // initialises b.a.b, not b.b
};
However, IMHO, that is already handled well enough by -Wmissing-field-initializers, which does not warn about your original code.
I get the same warning in Xcode 6.1.1 (the current version as of March 9, 2015). When I add the extra braces around each subobject I get an error. When I add an extra set of braces around the entire initialization list then the warning goes away. According to the standard specification 14882:2011 23.3.2.1 [array.overview] subsection 2 explicitly states
array<T, N> a = { initializer-list };
where initializer-list is a comma-separated list of up to N elements
whose types are convertible to T
result of code in Xcode 6.1.1 (below)
array<int, 2> key1 = {1, 2}; // warning: suggest braces around initialization of subobject
array<int, 2> key2 = { {1}, {2} }; // error: no viable overload =
array<int, 2> key3 = array<int, 2> { {1}, {2} }; // error: excess elements in struct initializer
array<int, 2> key4 = { {1, 2} }; // no warning and no error
When we look at 14882:2011 8.5 [dcl.init] subsection 1 we see that an 'initializer-list' can optionally contain an 'initializer-clause', which itself can be a 'braced-init-list'. So either way should be correct. Though based on the spec I personally think single braces shouldn't output a compiler warning for a std::array initializer-list, and double braces is overkill.
Clang 6.0 suppresses the warning about missing braces. The svn log says:
Suppress -Wmissing-braces warning when aggregate-initializing a struct with a single field that is itself an aggregate. In C++, such initialization of std::array types is guaranteed to work by the standard, is completely idiomatic, and the "suggested" alternative from
Clang was technically invalid.
So I would omit the braces and disable -Wmissing-braces for Clang prior to 6.0 if it needs to be supported.
When ignoring the Clang warning with -Wno-missing-braces, I would recommend to enable -Wmissing-field-initializers (or use -Wextra, which also includes it). Otherwise, you miss a useful warning like in this example:
#include <cstdio>
struct A
{
int i;
int arr[2];
int j;
};
void print(const A& a)
{
printf("i=%d, arr={%d,%d}, j=%d\n", a.i, a.arr[0], a.arr[1], a.j);
}
int main() {
A a = {1, 2, 3}; // this is the critical line
print(a); // output: i=1, arr={2,3}, j=0
A b = {1, {2}, 3};
print(b); // output: i=1, arr={2,0}, j=3
A c = {1, {2,0}, 3};
print(c); // output: i=1, arr={2,0}, j=3
return 0;
}
$ clang++ -Wall example.cpp
example.cpp:16:13: warning: suggest braces around initialization of
subobject [-Wmissing-braces]
A a = {1, 2, 3};
^~~~
{ }
1 warning generated.
$ clang++ -Wall -Wno-missing-braces example.cpp
(no warnings)
$ clang++ -Wall -Wno-missing-braces -Wmissing-field-initializers example.cpp
example.cpp:16:17: warning: missing field 'j' initializer
[-Wmissing-field-initializers]
A a = {1, 2, 3};
^
1 warning generated.
$ clang++ --version
clang version 3.8.1 (tags/RELEASE_381/final)
For comparison, this is what GCC does:
$ g++ -Wall -Wextra example.cpp
(no warning)
$ g++ -Wall -Wmissing-field-initializers example.cpp
example.cpp: In function ‘int main()’
example.cpp:16:17: warning: missing initializer for member ‘A::j’ [-Wmissing-field-initializers]
A a = {1, 2, 3};
^
In summary:
For Clang, I would recommend -Wno-missing-braces -Wmissing-field-initializers to silence the warning without loosing other useful warnings
GCC does not complain in the original std::array<int, 1> x = { 0 }; example, so there is no need to disable any warnings. However, I would recommend to enable -Wmissing-field-initializers (or use -Wextra), as it is not enabled by -Wall.
In c++ primer(5th), it mentioned:
When used with variables of built-in type, this form of initialization
has one
important property: The compiler will not let us list initialize variables of built-in type if the initializer might lead to the loss
of information:
longdouble ld = 3.1415926536;
int a{ld}, b = {ld}; // error: narrowing conversion required
int c(ld), d = ld; // ok: but value will be truncate
I compile the code using gcc4.8.1 , it only give a warning rather than an error.
g++ -W -Wall -Wextra -pedantic -std=c++0x -o m main.cpp
main.cpp: In function ‘int main()’:
main.cpp:64:13: warning: narrowing conversion of ‘ld’ from ‘long double’ to ‘int’ inside { } [-Wnarrowing]
int a{ld}, b= {ld};
^
main.cpp:64:22: warning: narrowing conversion of ‘ld’ from ‘long double’ to ‘int’ inside { } [-Wnarrowing]
int a{ld}, b= {ld};
Is there any flags that will turn on the feature of the important property ?
A quick search for "gcc diagnostic flag" turns up documentation resources.
Inside your program, you could do this:
#ifdef __GNUC__
# pragma GCC diagnostic error "-Wnarrowing"
#endif
There is a command-line option too: -Werror=narrowing, but since you want to alter the semantic meaning of the program itself according to GCC, putting it in the source code is probably more appropriate.
Note, when it makes a difference other than simple well-formedness, such as in overload selection, GCC does diagnose the condition correctly.
The standard never calls for errors or for warnings: the standard only requires an implementation to issue a diagnostic. Whether such a diagnostic takes the form of a compiler error, or a warning, or something entirely different from them both, is outside the scope of the standard.
Consider the following program:
#include <array>
int main()
{
std::array<int, 1> x = { 0 }; // warning!
x = { { 0 } }; // no warning
return 0;
}
The first initialization leads to warnings on gcc 4.7.2...
main.cpp:5:22: warning: unused variable ‘x’ [-Wunused-variable]
... and clang 3.1
main.cpp:5:28: warning: suggest braces around initialization of subobject [-Wmissing-braces]
std::array<int, 1> x = { 0 };
As far as the standard goes, there should be no difference between double or single curly braces, at least in this example.
There are two ways to deal with the warning:
Just turn it off
Fix the code, so the compiler is happy
What do you propose? IMHO, the double curly expression looks somewhat ugly. On the other hand, the warning might detect real problems in more complicated examples. Do you know an example where the warning would have helped you?
-Wmissing-braces will no longer be enabled in GCC's -Wall (for C++ mode), as of 4.8, for precisely the reason you describe. For current versions of GCC, either disable or ignore the warning, the code you have is written the way it should be.
The warning is probably meant to cover code such as
struct A { int a; int b; };
struct B { A a; int b; };
B b = {
1,
2 // initialises b.a.b, not b.b
};
However, IMHO, that is already handled well enough by -Wmissing-field-initializers, which does not warn about your original code.
I get the same warning in Xcode 6.1.1 (the current version as of March 9, 2015). When I add the extra braces around each subobject I get an error. When I add an extra set of braces around the entire initialization list then the warning goes away. According to the standard specification 14882:2011 23.3.2.1 [array.overview] subsection 2 explicitly states
array<T, N> a = { initializer-list };
where initializer-list is a comma-separated list of up to N elements
whose types are convertible to T
result of code in Xcode 6.1.1 (below)
array<int, 2> key1 = {1, 2}; // warning: suggest braces around initialization of subobject
array<int, 2> key2 = { {1}, {2} }; // error: no viable overload =
array<int, 2> key3 = array<int, 2> { {1}, {2} }; // error: excess elements in struct initializer
array<int, 2> key4 = { {1, 2} }; // no warning and no error
When we look at 14882:2011 8.5 [dcl.init] subsection 1 we see that an 'initializer-list' can optionally contain an 'initializer-clause', which itself can be a 'braced-init-list'. So either way should be correct. Though based on the spec I personally think single braces shouldn't output a compiler warning for a std::array initializer-list, and double braces is overkill.
Clang 6.0 suppresses the warning about missing braces. The svn log says:
Suppress -Wmissing-braces warning when aggregate-initializing a struct with a single field that is itself an aggregate. In C++, such initialization of std::array types is guaranteed to work by the standard, is completely idiomatic, and the "suggested" alternative from
Clang was technically invalid.
So I would omit the braces and disable -Wmissing-braces for Clang prior to 6.0 if it needs to be supported.
When ignoring the Clang warning with -Wno-missing-braces, I would recommend to enable -Wmissing-field-initializers (or use -Wextra, which also includes it). Otherwise, you miss a useful warning like in this example:
#include <cstdio>
struct A
{
int i;
int arr[2];
int j;
};
void print(const A& a)
{
printf("i=%d, arr={%d,%d}, j=%d\n", a.i, a.arr[0], a.arr[1], a.j);
}
int main() {
A a = {1, 2, 3}; // this is the critical line
print(a); // output: i=1, arr={2,3}, j=0
A b = {1, {2}, 3};
print(b); // output: i=1, arr={2,0}, j=3
A c = {1, {2,0}, 3};
print(c); // output: i=1, arr={2,0}, j=3
return 0;
}
$ clang++ -Wall example.cpp
example.cpp:16:13: warning: suggest braces around initialization of
subobject [-Wmissing-braces]
A a = {1, 2, 3};
^~~~
{ }
1 warning generated.
$ clang++ -Wall -Wno-missing-braces example.cpp
(no warnings)
$ clang++ -Wall -Wno-missing-braces -Wmissing-field-initializers example.cpp
example.cpp:16:17: warning: missing field 'j' initializer
[-Wmissing-field-initializers]
A a = {1, 2, 3};
^
1 warning generated.
$ clang++ --version
clang version 3.8.1 (tags/RELEASE_381/final)
For comparison, this is what GCC does:
$ g++ -Wall -Wextra example.cpp
(no warning)
$ g++ -Wall -Wmissing-field-initializers example.cpp
example.cpp: In function ‘int main()’
example.cpp:16:17: warning: missing initializer for member ‘A::j’ [-Wmissing-field-initializers]
A a = {1, 2, 3};
^
In summary:
For Clang, I would recommend -Wno-missing-braces -Wmissing-field-initializers to silence the warning without loosing other useful warnings
GCC does not complain in the original std::array<int, 1> x = { 0 }; example, so there is no need to disable any warnings. However, I would recommend to enable -Wmissing-field-initializers (or use -Wextra), as it is not enabled by -Wall.