vector<vector<int> > res;
res.emplace_back({1,2}); // change to res.push_back({1,2}); would work
This gives me 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 to make this work? Also, why an allocator is needed here?
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.
Take a look at the documentation for vector::emplace_back
. emplace_back
tries to create a new element in your vector, by calling the constructor for the new element with the arguments passed in. So basially, when you call emplace_back({1,2})
, it tries to pass {1,2}
in to a constructor, but since res
is a vector of vectors of ints, it's looking at vector constructors, none of which can take a brace-enclosed initializer list.
Also, take a look at the documentation for vector::push_back
. When push_back
is called, it creates a default object (in this case, a vector of ints) and copies the values into it. I would guess that the reason that push_back({1,2})
works is that the brace-enclosed initializer list creates a value-type, which push_back
accepts.
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