I defined the following
std::vector<std::pair<int,int> > my_vec;
my_vec.push_back( {1,2} ); //this works
my_vec.emplace_back( {1,2} ); // this doesn't work
std::pair<int,int> temp_pair = {1,2};
my_vec.emplace_back( temp_pair ); //this works
I am compiling with c++11. The third line is problematic, but I thought you can use emplace_back()
anywhere that you have push_back()
, but this is apparently wrong. Why does the third line not work?
emplace_back
takes a variadic parameter pack as argument:
template< class... Args > reference emplace_back( Args&&... args );
When you call it like this: emplace_back({1, 2})
you are calling it with one argument i.e. {1, 2}
and the Args
cannot be deduced. That is because of how the language has evolved. In C++ {1, 2}
doesn't have a type. It is a brace enclosed init-list and can be used in certain types of initializations, but all require the type of the initialized to be known. That is why temp_pair = {1,2};
works, because the type of temp_pair
is know and has a constructor matching (int, int)
.
Anyway emplace_back
wasn't supposed to be used like that, but like this instead:
my_vec.emplace_back(1, 2);
Also please note that even if these work:
my_vec.emplace_back(std::pair<int, int>{1, 2});
my_vec.emplace_back(temp_pair);
They shouldn't be used. They add no advantage over push_back. The whole point of emplace_back
is to avoid creating a temporary T
. The above calls all create the temporary std::pair<int, int>
.
but I thought you can use
emplace_back()
anywhere that you havepush_back()
For the most part that's correct. At least that was the intention. And you can indeed use it in your cese. You just have to adjust the syntax a little. So instead of push_back({1, 2})
you can use emplace_back(1, 2)
.
There is a situation where unfortunately you can't use emplace_back
: aggregates before C++20.
struct Agg
{
int a, b;
};
auto test()
{
Agg a{1, 2}; // ok, aggregate initialization
std::vector<Agg> v;
v.emplace_back(1, 2); // works only since C++20
}
This doesn't work before C++20 unless you add a constructor for Agg
. This was considered an open defect in the standard, but unfortunately they can't find a good solution to this. The problem is with how brace init initialization works and if you use it in generic code you can miss some constructors. For all the nitty-gritty details check this great post: Why can an aggreggate struct be brace-initialized, but not emplaced using the same list of arguments as in the brace initialization?