Rvalue References and Forwarding References in C++

Move Semantics

The Vector class below is used to explain lvalues and rvlaues and move semantics. Move semantics allow you to overloaded a class’s constructor and assignment operator with a new type of reference called an rvalue reference (see rvalue references and their role). Doing so allows the compiler to always choose the more effecient move constructor and move assignment operator when an rvalue is encountered. Below is a template Vector class with the usual copy constructor and assignment operator as well as void push_back(const T&) that take an const T&:

#include <memory>
#include <initializer_list>

template<class T>  class Vector {

   std::unique_ptr<T[]> p;

   int size;

   int current;

   void grow();

   static const int growth_factor = 2;
   static const int default_sz = 2;

   public:

     Vector() : p(std::make_unique<T[]>(Vector::default_sz )), size{Vector::default_sz}, current{0}
     {
     }

     Vector(std::initializer_list<T> lst) : p(std::make_unique<T[]>(Vector::default_sz )), size{Vector::default_sz}, current{0}
     {
        for (auto& x : lst) {
            push_back(std::move(x));
       }
     }

     Vector(const Vector<T>& lhs);

     Vector& operator=(const Vector<T>& lhs);

     void push_back(const T& t);

     void push_back(T&& t);

     T& operator[](int);

     const T& operator[](int) const;

     std::ostream& print(std::ostream& ostr) const
     {
        if (size != 0) {

        std::copy(p.get(), p.get() + current, std::ostream_iterator<T>(ostr, ", "));
        }
        return ostr;
     }

     friend std::ostream& operator<<(std::ostream& ostr, const Vector<T>& vec)
     {
         return vec.print(ostr);
     }

     int count() const { return size; }

     void* operator new (std::size_t size, void* ptr) noexcept;
};


template<class T> inline Vector<T>::Vector(const Vector& lhs) : p{new T[lhs.size]}, size{lhs.size}, current{lhs.current}
{
  std::copy(p.get(), lhs.p, lhs.p + lhs.size);

}

template<class T> inline Vector<T>::Vector(Vector<T>&& lhs) : p(std::move(lhs.p)), size{lhs.size}, current{lhs.current}
{
    lhs.size = 0;
}

template<class T> Vector<T>&  Vector<T>::operator=(const Vector& lhs)
{
   if (this != &lhs) {

       p = std::make_unique<T[]>(new T[lhs.size]);

       size = lhs.size;

       copy(p, lhs.p, lhs.p + lhs.size);
   }

   return *this;
}

template<class T> void Vector<T>::grow()
{
  auto new_size = size * Vector<T>::growth_factor;

  std::unique_ptr<T[]> ptr = std::make_unique<T[]>(new_size);

  for (auto i = 0; i < size; ++i) {

      ptr[i] = std::move(p[i]);
  }

  size = new_size;

  p = std::move(ptr);
}

template<class T> void Vector<T>::push_back(const T& t)
{
  if (current == size) {

     grow();
  }

  p[current++] = t;
}

template<class T> T& Vector<T>::operator[](int pos)
{
  if (pos >= size || pos < 0) {

      throw(std::out_of_range("pos not in range."));

  } else {

     return p[pos];
  }
}

template<class T> inline const T& Vector<T>::operator[](int pos) const
{
   return static_cast<T *>(this)->operator[](pos);
}

rvalue references and their role

An lvalue is object that has name, an object whose address can be taken. Examples of lvalues would be:

int i; // lvalue
int j = 8; // lvalue assigned rvalue

int& f2(); // f2() returns an lvalue

If an object is not an lvalue, it is an rvalue. An rvalue is a temporary object whose lifetime does not extend past the current line’s semicolon. You cannot take the address of an rvalue. See A Brief Introduction to Rvalue References. Below are some examples of rvalue and lvalues:

int i; // lvalue
int j = 8; // lvalue assigned rvalue

int f1(); // f1() returns an rvalue. We can't do &f1().
int& f2(); // f2() returns an lvalue
int&& f3(); // f3() returns an rvalue.

class X { //...};

X x1; // lvalue declared
X f4(); // returns rvalue
X& f5(); // returns lvalue

An rvalue reference is declared using &&:

int&& j = 8;
int&& f3(); // f3() returns an rvalue
int&& k = f3();
int v = 9;
int&& l = v; // error: cannot bind rvlue reference l to lvalue v.

The rvalue reference j above is not really of any value. While we can change the value of a literal using this trick

int&& j = 8;
j = 9;
cout << j;  // prints: 9

the temporay gets deleted once j goes out of scope, and this technique has no wide applicability. When the compiler see an rvalue, it thinks, “oh, this is an rvalue, let me see if the class method being invoked takes an rvalue reference, so I can invoke it.”

note:: rvalue reference variables are lvalues when used in expressions.

#include <iostream>
#include <utility>

void f(int& x) {
    std::cout << "lvalue reference overload f(" << x << ")\n";
}

void f(const int& x) {
    std::cout << "lvalue reference to const overload f(" << x << ")\n";
}

void f(int&& x) {
    std::cout << "rvalue reference overload f(" << x << ")\n";
}

int main() {
    int i = 1;
    const int ci = 2;
    f(i);  // calls f(int&)
    f(ci); // calls f(const int&)
    f(3);  // calls f(int&&)
           // would call f(const int&) if f(int&&) overload wasn't provided
    f(std::move(i)); // calls f(int&&)

    // rvalue reference variables are lvalues when used in expressions
    int&& x = 1;
    f(x);            // calls f(int& x)
    f(std::move(x)); // calls f(int&& x)
}

note:: rvalue reference parameters are lvalues

class Base {
  // snip...
 public:
  Base(const Base& b);
  Base(Base&& b);
  //snip...
};

class Derived {
  // snip...
 public:
  Derived(const Derived& d);
  Derived(Derived&& d);
  //snip...
};

Derived::Derived(Derived&& d) : Base(std::move(d)), ... {}

Although d is a reference to an rvalue, d itself is an lvalue because it has a name and its address can be taken; and so it must be cast to an rvalue using std::move(d).

Overloading Constructors and Assignment Operators with rvalue references

When C++11 introduced rvalue references, it allowed constructors and assignment operators to be overloaed with rvalue references, and this allows the compiler to now branch at compiler time depending on whether the constructor or assignment operator is being passed an lvalue or an rvalue. But how do you implement the constructor and assigment operator that take an rvalue reference?

Implementation of move constructor and move assignment operator

The move constructor and move assignment, both of which take rvalue references, both read from and write to the rvalue reference parameter. They perform a shallow copy of its resourses, and then, as in the example below, set the rvalue object’s length to 0 and it’s pointer p is set to nullptr to prevent the memory being deallocated when the rvalue’s destructor is called.

#include <memory>
#include <initializer_list>

template<class T>  class Vector {

   std::unique_ptr<T[]> p;

   int size;

   int current;

   void grow();

   static const int growth_factor = 2;
   static const int default_sz = 2;

   public:

     Vector() : p(std::make_unique<T[]>(Vector::default_sz )), current{0}
     {
     }

     Vector(std::initializer_list<T> lst)
     {
       for (auto& x : lst) {
            push_back(x);
       }
     }

     Vector(const Vector<T>& lhs);

     Vector(Vector<T>&& lhs); // move constructor

     Vector& operator=(const Vector<T>& lhs);

     Vector& operator=(Vector<T>&& lhs); // move assignment operator

     void push_back(const T& t);

     void push_back(T&& t);

     template<class... ARGS> void emplace_back(ARGS&& ... args);

     T& operator[](int);

     const T& operator[](int) const;

     std::ostream& print(std::ostream& ostr) const
     {
        std::copy(p.get(), p.get() + current, std::ostream_iterator<T>(ostr, "\n"));
        return ostr;
     }

     friend std::ostream& operator<<(std::ostream& ostr, const Vector<T>& vec)
     {
         return vec.print(ostr);
     }

     void* operator new (std::size_t size, void* ptr) noexcept;
};


template<class T> inline Vector<T>::Vector(const Vector& lhs) : p{new T[lhs.size]}, size{lhs.size}, current{lhs.current}
{
  std::copy(p.get(), lhs.p, lhs.p + lhs.size);
}

template<class T> inline Vector<T>::Vector(Vector<T>&& lhs) : p(std::move(lhs.p)), size{lhs.size}, current{lhs.current}
{
    lhs.size = 0;
}

template<class T> Vector<T>&  Vector<T>::operator=(const Vector& lhs)
{
   if (this != &lhs) {

       p = std::make_unique<T[]>(new T[lhs.size]);

       size = lhs.size;

       copy(p, lhs.p, lhs.p + lhs.size);
   }

   return *this;
}

template<class T> Vector<T>&  Vector<T>::operator=(Vector&& lhs)
{
   if (this != &lhs)  {

       p = std::move(lhs.p); // std::move() casts an lvalue to an rvalue.

       size = lhs.size;

       lhs.size = 0;
   }

   return *this;
}

template<class T> void Vector<T>::grow()
{
  auto new_size = size * Vector<T>::growth_factor;

  std::unique_ptr<T[]> ptr = std::make_unique<T[]>(new_size);

  for (auto i = 0; i < size; ++i) {

      ptr[i] = std::move(p[i]);
  }

  size = new_size;

  p = std::move(ptr);

  ++current;
}

template<class T> void Vector<T>::push_back(const T& t)
{
  if (current == size) {

     grow();
  }

  p[current++] = t;
}

template<class T> T& Vector<T>::operator[](int pos)
{
  if (pos < size && pos > 0) {

     return p[pos];

  } else {

    throw(std::out_of_range("pos not in range."));
  }
}

template<class T> const T&  Vector<T>::operator[](int pos) const
{
  if (pos < size && pos > 0) {

     return const_cast<const T&>(p[pos]);

  } else {

    throw(std::out_of_range("pos not in range."));
  }
}

template<class T> void  Vector<T>::push_back(T&& t)
{
  if (current == size) {
     grow();
  }
  p[current++] = std::move( t );
}

template<class T> template<class... ARGS> void Vector<T>::emplace_back(ARGS&& ... args)
{
   if (size == current) {

       grow();
   }

   T *ptr = p.get();

   T *location = ptr + current;

   new(location) T{std::forward<ARGS>(args)...};

   current++;
}

Obviously the constructor and assignment operator overloaded to take an rvalue reference are more efficient that their copy constructor and copy assignment operator counterparts. For example

Vector<int> v1{1, 5, 12};
Vector<int> v2{v2}; // invokes copy constructor
Vector<int> v2{v{2, 6, 16}}; // invokes move constructor Vector::Vector(Vector&&)
template<class T> void f(Vector<T>&& v);
f(Vector<intT>{11, 19, 29}); // invokes move constructor Vector::Vector(Vector&&)

Rvalue References and Derived classes

Is an rvalue reference parameter itself an rvalue or an lvalue? The answer is, an rvalue reference that has a name is considered an lvalue because an rvalue reference parameter that has a name can have its address taken. It is therefore not a temporary. So when it “has a name” the rvalue reference parameter itself is an lvalue within the scope of the method. This has implications for how move semantics must be implemented in derived classes:

class Base {
    char *p;
    int length;
  public:
   //...snip
   Base(Base&& lhs)
   {
     p = lhs.p;
     lhs.p = nullptr;
     length = p.length;
     p.length = 0;
   }
   //...snip
};

Derived : public Base {
   public:
     Derived(Derived&& d) : Base(std::move(d)) {}
};

Since d is an lvalue, the implementation of Derived(Derived&& d) requires casting it to an rvalue so that the Base move constructor is called and not the copy constructor.

Note, Since std::move() works correctly on both rvalues and lvalues, no harm is done when passing it an rvalue: it still returns an rvalue. The g++ version of std::move() is shown below. Its argument is of generic type T&&. This looks like an rvalue reference, but it works differently than an ordinary rvalue reference, say, for example, std::string&&, where the type is specified or hard-coded. T&&` binds to both lvalues and rvalues, and is known as a forwarding reference. When it binds to an lvalue, T resolves to an lvalue reference, and when an rvalue is passed T resolves to the underlying nonreference type. We can see this by implementing a version of Remove_reference and its partial template specializations that contains a static method called describe(), which move() invokes:

template<typename T> constexpr typename std::Remove_reference<T>::type&& move(T&& __t) noexcept
{
  return static_cast<typename std::Remove_reference<T>::type&&>(__t);
}

// Remove_reference defined
template<typename _Tp>
  struct Remove_reference
  {
    static void describe()
    {
      cout << "In non-specialization Remove_reference<_Tp> constructor" << endl;
    }
    typedef _Tp   type;
};

// Remove_reference partial template specializations
template<typename _Tp>
  struct Remove_reference<_Tp&> {
    static void describe()
    {
      cout << "In partial template specialization Remove_reference<_Tp&> constructor" << endl;
    }
    typedef _Tp   type;
};

template<typename _Tp>
  struct Remove_reference<_Tp&&> {
    static void describe()
    {
     cout << "In partial template specialization Remove_reference<_Tp&&> constructor" << endl;
    }
     typedef _Tp  type;
};

template<typename T>
constexpr typename Remove_reference<T>::type&& move(T&& arg)
{
  Remove_reference<T>::describe();

  return static_cast<typename Remove_reference<T>::type&&>(arg);
}

string a{"test"};

string&& rval = move(a);

string {move(string{"xyz"})};

This results in the output:

In partial template specialization Remove_reference<_Tp&> constructor
In non-specialization Remove_reference<_Tp> constructor

In the case of string {move(string{"xyz"})};, T resolves to std::string. This is what is instantiated step-by-step:

constexpr typename Remove_reference<std::string>::type&& move(std::string&& arg)
{
  Remove_reference<std::string>::describe();

  return static_cast<typename Remove_reference<std::string>::type&&>(arg);
}

which simplies to:

constexpr typename std::string&& move(std::string&& arg)
{
  Remove_reference<std::string>::describe();

  return static_cast<typename std::string&&>(arg);
}

which is a rvalue cast (to something that does not have a name). In the case of move(a), T resolves to std::string&. Again, this is what is instantiated step by step:

constexpr typename Remove_reference<std::string&>::type&& move(std::string&  && arg)
{
  Remove_reference<std::string&>::describe();

  return static_cast<typename Remove_reference<std::string&>::type&&>(arg);
}

If we applying the reference collapsing rules of C++11, this becomes:

constexpr typename Remove_reference<std::string&>::type&& move(std::string& arg)
{
  Remove_reference<std::string&>::describe();

  return static_cast<typename Remove_reference<std::string&>::type&&>(arg);
}

which simplies to

constexpr std::string&&  move(std::string& arg)
{
  Remove_reference<std::string>::describe();

  return static_cast<typename std::string&&>(arg);
}

And again as before, this casts arg to rvalue reference that does not have a name.

std::move() Implementation

template<typename T>
   constexpr typename std::remove_reference<T>::type&&
   move(T&& __t) noexcept
   {
     return static_cast<typename std::remove_reference<T>::type&&>(__t);
   }

Why is the return type of std::move() is constexpr typename std::remove_reference<_Tp>::type&& instead of T&&? Recall that when an lvalue is passed to std::move() like below

using namespace std;

class X {
     //snip...
   public:
     X(const X&);
     X(X&&);
     //snip...
};

X x1;

X x2 = move(x1);

then T binds as X&, and the move(x1) instantiated (before reference collapsing is done) is

constexpr typename std::remove_reference<X&>::type&&
move(X& && __t) noexcept
{
  return static_cast<typename std::remove_reference<X&>::type&&>(__t);
}

and after applying reference collapsing, it is

constexpr typename std::remove_reference<X&>::type&&
move(X& __t) noexcept
{
  return static_cast<typename std::remove_reference<X&>::type&&>(__t);
}

and the instantiation of remove_reference<X&>::type is simply X. Thus move(x1) is:

constexpr X&&
move(X& __t) noexcept
{
  return static_cast<X&&>(__t);
}

Had move() been implemented as

template<typename T>
   constexpr T&&
   move(T&& __t) noexcept
   {
     return static_cast<T&&>(__t);
   }

then it would have been instantiated as

constexpr X& &&
move(X& && __t) noexcept
{
  return static_cast<X& &&>(__t);
}

and after applying reference collapsing, we would have

constexpr X&
move(X& __t) noexcept
{
  return static_cast<X&>(__t);
}

as the instantiation of move(x1), and move(x1) would still be an lvalue.

If move() is passed an rvalue, then the instantion of

template<typename T>
   constexpr T&&
   move(T&& __t) noexcept
   {
     return static_cast<T&&>(__t);
   }

would work fine. For example:

X createX();

X x = move(createX());

would instantiate

constexpr X&&
move(X&& __t) noexcept
{
  return static_cast<X&&>(__t);
}

and a nameless rvalue (known as a xvalue) would be returned. remove_reference<T>::value&& is needed to ensure an lvalue is converted to an rvalue (or more specifically a xvalue).

Move Conclusion

move(T&&) is non-overloaded function template that casts its argument to an rvalue. It works both with lvalue and rvalue arguments. It uses the partial template specializations provided by Remove_reference<T> to do this.

Note

The C++ standard library’s Remove_reference is simply remove_reference (with a lowercase r). The version above used Remove_reference (with an uppercase R), so that it would not conflict with the actual std::remove_reference in the standard library, which automatically gets included when <iostream> is included in main.cpp and its methods are used, as they were in the example code above.

Value Categories

Perfect Forwarding

This section discusses the use of forwarding references to implement perfect forwarding of parameters used to do in_place_construction.

Forwarding References

A forwarding reference is a template function parameter of type T&& such as

template<typename T> void sample(T&& t);

It looks just like an rvalue reference, but when && is used in function template as above, it is called a forwarding refernence. Unlike an rvalue reference, a forwarding reference T&& can bind to both rvalues and lvalues. Forwarding reference take advantage of the new C++11 reference collapsing rules. In C++11 unlike previous versions, you can syntactically have a reference to a reference. In this case, the following reference collapsing rules apply: references to references:

  • T& & becomes T&
  • T& && becomes T&
  • T&& & becomes T&
  • T&& && becomes T&&

Except in the case of T&& &&, the final result of reference collapsing is always T&.

The Purpose of Forwarding References

Unlike an rvalue reference, a forwarding reference T&& can bind to both rvalues and lvalues. It can bind to both const and non-const objects. It can bind to mutable and volitale. In essence, it can bind to any type. When a lvalue, say, of type X is passed to a template function argument of generic type T&&, then T becomes X&, and therefore T&& becomes X& &&, which after applying the reference collapsing rules becomes simply X&. On the other hand, when an rvalue of type X is passed, T becomes X, and T&& is thus simply X&&.

Thus an lvalue of type X binds as X& and an rvalue binds as X&&. We can see this in the code below:

#include <vector>
template<class T> struct state_type {
 using type = T;
 static void describe()
 {
    cout << "In non-specialization of struct state_type<T>" << endl;
 }
};

template<class T> struct state_type<T&> {
 using type = T;
 static void describe()
 {
   cout << "In partial template specialization of struct state_type<T&>" << endl;
 }
};

template<class T> struct state_type<T&&> {
 using type = T;
 static void describe()
 {
   cout << "In partial template specialization of struct state_type<T&&>" << endl;
 }
};

template<class ARG> void sample(ARG&& arg)
{
   state_type<ARG>::describe();
}

using namespace std;
vector<int> v{1, 2, 3, 4};
sample(v);
sample(vector<int>{5, 6, 7, 8});
sample(move(v));

This will result in output of:

In partial template specialization of struct state_type<T&>
In non-specialization of struct state_type<T>
In non-specialization of struct state_type<T>

For the lvalue v in sample(v);, ARG resolves to vector<int>&, and the instantiation of sample() is

void sample(vector<int>& && arg)
{
   state_type<vector<int&>::describe();
}

Applying reference collapsing rules for references this becomes

void sample(vector<int>& arg)
{
   state_type<vector<int&>::describe();
}

So we see arg binds as an lvalue reference. In the case of sample(vector<int>{5, 6, 7, 8});, ARG resolves to vector<int>, and the instantiation of sample looks like this:

void sample(vector<int>&& arg)
{
   state_type<vector<int>>::describe();
}

In this case arg binds as a rvalue reference. We can use these binding rules for function templates as the first step in writing a template function that perfectly forwards its parameters leaving the paramters type intact.

Now take this factory method:

class A { // trivial example
   std::string str;
  public:
    A(std::string& lhs) : str(lhs)
    {
      cout << " A::A(std::string& lhs) invoked." << endl;
    }

    A(std::string&& lhs)
    {
      cout << " A::A(std::string&& lhs) invoked." << endl;
    }
};

template<class T, class ARG> std::shared_ptr<T> factory(ARG&& arg)
{
   state_type<ARG>::describe();

   return std::shared_ptr<T>{new T(arg)};  // fails to invoke A(string&&) when string is rvalue.
}

Note the output of the code below, where first an lvalue is passed to factory<T>(ARG&& arg) and then an rvalue:

string lvaluestr{"lvaluestr"};

shared_ptr<A> ptr1 { factory<A>(lvaluestr) };

shared_ptr<A> ptr2 { factory<A>(string{"rvaluestr"}) };

The output is:

In partial template specialization of struct state_type<T&>
 A::A(std::string& lhs) invoked.
In non-specialization of struct state_type<T>
 A::A(std::string& lhs) invoked.

factory<T>(ARG&& arg) correctly forwarded the lvalue reference, but not the rvalue reference. Instead it got passed as lvalue references. Why? Why did shared_ptr<A> ptr2 { factory<A>(string{"rvaluestr"}) }; fail in invoking A::A(A&&)?

The reason is, arg is not an lvalue within the body of factory–even though the type of arg is rvalue reference! Remember than an rvalue reference, if it has a name, is an lvalue. So we need to remove the name with a cast:

template<class T, class ARG> std::shared_ptr<T> factory(ARG&& arg)
{
   state_type<ARG>::describe();

   return std::shared_ptr<T>{ new T( static_cast<ARG&&>(arg) ) };  // Cast returns a nameless parameter.
}

Now when "lvaluestr" is passed, ARG becomes string& and so ARG&& becomes string&&&, and after applying the reference collapsing rules is simply string&, and static_cast<string&>(arg) is still an lvalue. When an rvalue is passed; however, the lvalue arg is cast to a nameless rvalue.

The standard library provides forward<T>(std::remove_reference<T>::type&) to do this static_cast, and ith looks like this:

template<class T>
T&& forward(typename remove_reference<T>::type& a) noexcept
{
  return static_cast<T&&>(a);
}

If you use just T& instead of remove_reference<T>::type& in the defintion of std::forward, perfect forwarding still works just fine. However, as Thomas Becker explains: “it works fine only as long as we explicitly specify Arg as the template argument of std::forward. The purpose of the remove_reference in the definition of std::forward is to force us to do so.” If we don’t explicitly supply the template argument when invoking forward(), a compile error results; for example

template<class _Tp> void f(_Tp&& t)
{
    cout << "t = " << forward(t);
}
f(10);

results in:

/usr/include/c++/7/bits/move.h:73:5: note: candidate: template<class _Tp> constexpr _Tp&& std::forward(typename std::remove_reference<_From>::type&)
     forward(typename std::remove_reference<_Tp>::type& __t) noexcept
     ^~~~~~~
/usr/include/c++/7/bits/move.h:73:5: note:   template argument deduction/substitution failed:
main.cpp:74:30: note:   couldn't deduce template parameter ‘_Tp’
     cout << "t = " << forward(t);

Returning to our original example:

template<typename _Tp>
  constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
{
  return static_cast<_Tp&&>(__t);
}

We now use forward in our factory() function:

string lvaluestr{"lvaluestr"};

shared_ptr<A> ptr1 { factory<A>(lvaluestr) };

shared_ptr<A> ptr2 { factory<A>(string{"rvaluestr"}) };

template<class T, class ARG> std::shared_ptr<T> factory(ARG&& arg)
{
   state_type<ARG>::describe();

   return std::shared_ptr<T>{ new T( std::forward<T>(arg) ) };  // forward returns a nameless parameter.
}

When factory<A>(lvaluestr) is called, again, ARG resolves to string& and applying reference collapsing, we have this instantiation of factory:

std::shared_ptr<A> factory(string& arg)
{
   return std::shared_ptr<A>{ new A( std::forward<T>(arg) ) };
}

For the accompanying forward instantiation, the partial template specialization for lvalue references is applied and std::remove_reference<string&>::type& `` resolves to ``string& and so forward() is instantiated as:

constexpr string& forward(string& __t) noexcept
{
   // static_cast<string& &&> collpases to static_cast<string&> below:
   return static_cast<string&>(__t);
}

So the complete instantiation of factory<A>(lvaluestr) is:

std::shared_ptr<A> factory(string& arg)
{
   return std::shared_ptr<A>{ new A( static_cast<string&>(arg) ) };
}

which results in the A::A(std::string&) being invoked!

When factory<A>(string{"rvaluestr}) is called, again, ARG resolves to string, and we have this instantiations of factory:

std::shared_ptr<A> factory(string&& arg)
{
   return std::shared_ptr<A>{ new A( std::forward(arg) ) };
}

and the accompanying instantiation of forward:

// remove_reference<string>::type& resolved to string&
constexpr string&& forward(string& __t) noexcept
{
   return static_cast<string&&>(__t);
}

So finally factory<A>(string{"rvaluestr}) resolves to:

std::shared_ptr<A> factory(string&& arg)
{
   return std::shared_ptr<A>{ new A( static_cast<string&&>(arg) ) };
}

which will cause the A::A(string&&) constructor will be invoked!

Application of Perfect Forwarding

Below Vector now has a new template member function emplace_back that takes variadic forwarding references.

template<class T> Vector {
  // snip...(as above)
  public:
  // snip...(as above)
    template<class... ARGS> void emplace_back(ARGS&& ... args);
};

template<class T> template<class... ARGS> void Vector<T>::emplace_back(ARGS&& ... args)
{
   if (current == size) { // If new value won't fit...

      grow();           // ...grow the vector
   }

   new(p + current) T{std::forward<ARGS>(args)...}; // Use placement new to construct the object in existing memory.

   current++;
}

class Employee {

     std::string name
     int age;
     int salary;
  public:
     Employee() {}
     Employee(const std::string& _name, int _age, int _salary) :\
             name{_name}, age{_age}, salary{_salary} {}

     Employee(Employee&& e) : name{std::move(e.name)}, age{e.age}, salary{e.salary} {}
     // snip...
};

Vector<Employee> v;

v.push_back(Employee{"John Doe", 15, 0});
v.emplace_back("Bob Smith", 45, 80000);

emplace_back() creates the new vector element in-place, in the vector itself, using the object’s forwarded parameters, and thus eliminating the creation and moving of a temporary object into the vector.

Overloading involving both rvalues and forwarding references

What happens when a function template is overloaded with two versions: one taking an lvalue reference and the other a forwarding reference? For example:

template<typename T> void g(T& param) noexcept
{
  cout << "In g(T& param)" << endl;
}

template<typename T> void g(T&& param) noexcept
{
  cout << "In g(T&& param)" << endl;
}

int x = 20;
g(11);
g(x);

In this case, the lvalue reference version always wins, so the output would be:

In g(T&& param)
In g(T& param)

However, if we remove the overload on the lvalue reference See these links for move above forwarding references:

template<typename T> void g(T&& param) noexcept
{
  cout << "In g(T&& param)" << endl;
}

int x = 20;
g(11);
g(x);

Then the output is:

In g(T&& param)
In g(T&& param)

as one would expect.

Further articles on forwarding references:

  1. Modern C++ Features – in place construction
  2. https://www.youtube.com/watch?v=ECoLo17nG5c
  3. http://eli.thegreenplace.net/2014/perfect-forwarding-and-universal-references-in-c/

Conclusion

We have seen when an lvalue is passed to std::forward, a nameless lvalue is returned; however, when an rvalue is passed to forward, a nameless rvalue is returned. This perfectly forwards the parameters, resulting in the correct method always being invoked and its paramters perfectly forwared.