Search code examples
c++c++11copymovestd-pair

Map moving emplace with lvalue


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.


Solution

  • 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