dimanche 1 février 2015

Why do the C++11 std::initializer_list constructor overloading rules exist?

I can't seem to find or think of a justification for the following code:



std::vector<int> a{1,2} // calls (7)
std::vector<int> a(1,2) // calls (2)

// constructors from http://ift.tt/1pUDKXt
vector( std::initializer_list<T> init,
const Allocator& alloc = Allocator() ); // (7)

explicit vector( size_type count,
const T& value = T(),
const Allocator& alloc = Allocator()); // (2)


Different functions are called based on which method of construction you use ({} vs ()) and this seems extremely perverse to me. Why is std::initializer_list preferred to other functions that would otherwise perfectly match the given parameters? I know that constructor 2 above was deprecated in C++11, presumably because of this change, but I still cannot reason about why this is the case. The only benefit I can see for this behaviour is that you can initialize a container with specific values and only require a single pair of braces; std::vector<int> a{1,2} vs std::vector<int> a{{1,2}}. But, to me at least, this certainly doesn't outweight the ambiguity and the changes to overload resolution that this has imposed. According to Scott Meyers in Effective Modern C++, std::make_unique and std::make_shared need to explicitly state which form is used for construction as part of their interface (because of the overload resolution). That seems ridiculous to me.


I concede that I must be missing something, but I'm just not sure what it is. Please not that I just used std::vector as an example and I'm asking about the feature in general.


Aucun commentaire:

Enregistrer un commentaire