#include <iostream>
struct X {
X(std::initializer_list<int> list) { std::cout << "list" << std::endl; }
X(float f) { std::cout << "float" << std::endl; }
};
int main() {
int x { 1.0f };
X a(1); // float (implicit conversion)
X b{1}; // list
X c(1.0f); // float
X d{1.0f}; // list (narrowing conversion) ARG!!!
// warning: narrowing conversion of '1.0e+0f' from 'float' to 'int'
// inside { } [-Wnarrowing]
}
Is there any other way of removing std::initializer_list
from an overload list (i.e., making the non-list ctors more favorable) instead of using the ()-initialization, or at least prohibiting narrowing conversion to happen (apart from turning warning into error)?
I was using http://coliru.stacked-crooked.com/ compiler which uses GCC 4.8.
Actually, a program containing a narrowing conversion in a brace list initializer is ill-formed. I am not sure why the compiler just gives you a warning, but it definitely should issue an error here (FWIW, Clang does that).
Also notice, that this is a narrowing (and therefore illegal) conversion as well:
int x { 1.0f }; // ERROR! Narrowing conversion required
Per paragraph 8.5.4/3 of the C++11 Standard:
List-initialization of an object or reference of type T is defined as follows:
— If
T
is an aggregate, aggregate initialization is performed (8.5.1). [...]— Otherwise, if the initializer list has no elements [...]
— Otherwise, if
T
is a specialization ofstd::initializer_list<E>
, [...]— Otherwise, if
T
is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed. [...]
To be more precise, the Standard only says that a "diagnostic" is required in this case, and a warning is a diagnostic, so the compiler's behavior is conforming - but I believe emitting an error would be a better behavior.
That looks like a compiler error. You should be getting an error instead of a warning. Brace initialization should never implicitly narrow.
From the standard (§ 8.5.4)
struct B { B(std::initializer_list<int>); }; B b1 { 1, 2 }; // creates initializer_list<int> and calls constructor B b2 { 1, 2.0 }; // error: narrowing
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With