how to use std::vector::emplace_back for vector<vector<int> >?

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


@Mark's answer is pretty correct. Now let's consider a more practical case. After some proper operations, you've collected some data with vector<int>, and feel like pushing it into vector<vector<int>>:

std::vector<std::vector<int>> res;

for (int i = 0; i < 10000; ++i) {
    //
    // do something
    //
    std::vector<int> v(10000, 0);  // data acquired
    res.push_back(v);
}

It's not like assigning values you already know. Utilizing std::initializer_list is probably no longer a solution. In such cases, you may use std::move (along with either emplace_back or push_back is acceptable)

for (int i = 0; i < 10000; ++i) {
    std::vector<int> v(10000, 0);  // will become empty afterward
    res.emplace_back(std::move(v));  // can be replaced by 
                                     // res.push_back(std::move(v));
}

The performance is more or less improved. You can still be benefited from the concept of xvalue move-insertion, constructing objects by move-constructor rather than copying.

UPDATE

The reason that res.push_back(move(v)) works is because they overload the method std::vector::push_back(value_type&& val) after C++11. It is made to support rvalue reference deliberately.

Tags:

C++

C++11

Vector