I am not sure if I understand correctly this code:
template<typename M>
void add(M& m,int i, std::string s)
{
m.emplace(i,std::move(s));
}
int main()
{
std::map<int,std::string> m;
add(m,1,"foo");
}
When add
is called, the std::string
and the int
are copied. The method emplace
construct a std::pair
which is moved into the std::map
(no copy needed ). But the copy of int
is a lvalue while the copy of std::string
is cast to a rvalue, therefore which constructor is called to construct the std::pair
? Since one argument cannot be moved, I suppose that an additional copy take place here. Is it right? Obviously, if I cast also the copy of int
to a rvalue, I would expect no additional copies.
This constructor is called:
template< class U1, class U2 >
pair( U1&& x, U2&& y );
In this case x
and y
are not rvalue references but universal references. Long short story short, an lvalue (in this case the int
) collapses to an lvalue reference and an rvalue (in this case the std::string
) to an rvalue reference because of your std::move()
.
The instantiated constructor looks like this:
pair( int& x, std::string&& y );
Scott Meyers explains it much better https://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers