Why are there C ++ 11 constructor overload rules std :: initializer_list?

It seems I do not think and cannot find an excuse for the following code:

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

// constructors from http://en.cppreference.com/w/cpp/container/vector/vector
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)

The various functions are named based on which building method you use ( {}vs ()), and that seems extremely perverse to me. Why do std::initializer_listthey prefer other functions that otherwise would ideally fit these parameters? I know that the constructor 2above was deprecated in C ++ 11, presumably due to this change, but I still cannot explain why this is so. . The only advantage I see in this behavior is that you can initialize a container with specific values ​​and require only one pair of curly braces; std::vector<int> a{1,2}vsstd::vector<int> a{{1,2}}. But, at least, at least, of course, this does not eliminate the ambiguity and changes in the overload resolution that it imposed. According to Scott Meyers in Effective Modern C ++, std::make_uniqueand std::make_sharedit is necessary to explicitly indicate which form is used to build as part of their interface (due to overload resolution). It seems funny to me.

I admit that I'm missing something, but I'm just not sure what it is. Please note that I just used std::vectoras an example, and I ask about this function in general.

+4
source share
1 answer

++ 11: , . , , : "auto" , . , .

: , . , !

, , , , std::vector "" .

, ++ , <cstdarg>, C. ( )

?

#include <iostream>
#include <vector>
#include <typeinfo>

using namespace std;


vector<int> func (const vector<int> &a) { //works
//auto func (const vector<int> &a) -> vector<int> { //works
//auto func (const vector<int> &a) { //don't even compile, "returns a initializer list" error
    for (int i: a) {
        cout << "My " << i << endl;
    }

    return {20 , 30};
}

int main()
{
    //play with anonymous functions
    auto y = [ ](vector<int> e) { return e; }; //works
    vector<int> x = y({20, 30});
    //auto y = [ ](){ return {20, 30}; }; //don't even compile, "returns a initializer list" error
    //vector<int> x = y();

    //play with initialization
    //vector<int> x = {2,2,20,30}; //works
    //vector<int> x{2,2,20,30}; //works
    //auto x = vector<int>{2,2,20,30}; //works
    //Bellow, a common mistake of people initializing a int to a auto, like auto x = { 1 }
    //auto x = {2,2,20,30}; //wrong, but compiles, its a initializer list
    //auto x{2,2,20,30}; //wrong, but compiles, its a initializer list

    //Play with return types
    //vector<int> x = func(vector<int>(2,2));  //works only with vector<int> and auto with trailing type
    //vector<int> x(func(vector<int>(2,2))); //works only with vector<int> and auto with trailing type
    //vector<int> x{func(vector<int>(2,2))}; //works only with vector<int> and auto with trailing type
    //auto x = func(vector<int>(2,2));  //works only with vector<int> and auto with trailing type
    //auto x(func(vector<int>(2,2))); //works only with vector<int> and auto with trailing type

    cout << typeid(x).name() << endl;
    for (int i: x) {
        cout << "My " << i << endl;
    }

    return 0;
}
+3

All Articles