c++c++11vectorstdvectoremplace

How do I use std::vector::emplace_back with vector<vector<int>>?


vector<vector<int>> res;
res.emplace_back({1,2}); // change to res.push_back({1,2}); would work

This gives me the error:

main.cpp:61:25: error: no matching function for call to ‘std::vector<std::vector<int> >::emplace_back(<brace-enclosed initializer list>)’
main.cpp:61:25: note: candidate is:
In file included from /usr/include/c++/4.7/vector:70:0,
                 from /usr/include/c++/4.7/bits/random.h:34,
                 from /usr/include/c++/4.7/random:50,
                 from /usr/include/c++/4.7/bits/stl_algo.h:67,
                 from /usr/include/c++/4.7/algorithm:63,
                 from miscalgoc.hpp:1,
                 from main.cpp:1:
/usr/include/c++/4.7/bits/vector.tcc:92:7: note: void std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {}; _Tp = std::vector<int>; _Alloc = std::allocator<std::vector<int> >]

How do I make this work? Also, why is an allocator needed here?


Solution

  • The problem is that function template arguments doesn't deduce std::initializer_list from a braced-init-list (like { 1, 2 }).

    Example:

    #include <initializer_list>
    #include <type_traits>
    
    
    template<typename T>
    void func(T arg) {
    }
    
    
    int main() {
        auto init_list = {1, 2};    // This works because of a special rule
        static_assert(std::is_same<decltype(init_list), std::initializer_list<int>>::value, "not same");
    
        func(std::initializer_list<int>{1, 2});     // Ok. Has explicit type.
    
        func({1, 2});   // This doesn't because there's no rule for function
                        //      template argument to deduce std::initializer_list
                        //      in this form.
    }
    

    Live example

    std::vector::emplace_back() is a function template with its arguments being deduced. So passing it {1, 2} will not work because it couldn't deduce it. Putting an explicit type to it

    res.emplace_back(std::initializer_list<int>{1,2});
    

    would make it work.

    Live example