If I'm constructing a non-trivial container like a custom map for example,
and want to share code between the emplace
and insert
functions, one approach would be to have the insert
function simply call emplace
with the supplied element as the argument.
eg.:
template<typename... args>
iterator emplace(int id, args &&... params)
{
// Do complex stuff here, get a location
*location = value_type(std::forward<args>(params) ...);
}
iterator insert(int id, const value_type &element)
{
emplace(id, element);
}
Which in the case of insert &
should simply call the copy constructor if I understand correctly?
However in the case of insert &&
it becomes a little more confusing:
iterator insert(int id, value_type &&element)
{
emplace(id, std::move(element));
}
std::move
casts element to an xvalue, which is fine - but will std::forward
handle this appropriately? ie. for a non-trivial value_type
with a non-default move constructor, will the emplace
construction line above correctly call the move constructor?
Which in the case of
insert &
should simply call the copy constructor if I understand correctly?
Yes, you're giving std::forward
a const lvalue in this scenario, and std::forward
yields a const lvalue.
With that, the copy constructor is called.
std::move
casts element to an xvalue, which is fine - but willstd::forward
handle this appropriately?
Yes. std::forward
turns rvalues into xvalues and lvalues into lvalues.
As long as you don't hand it an lvalue, it won't give you an lvalue.
This subsequently means that the move constructor will be called, as intended.
In args &&... params
, args
deduces to value_type
, making params
an rvalue reference when the function template is instantiated.
The first overload of std::forward
is called, and std::forward<args>(params)
yields an xvalue.
It's actually quite common to implement push_back
or insert
for containers in terms of emplace_back
or emplace
.