Home C++ Introduction Decisions Loops Input/Output Functions Stack and Heap References Arrays Searching and Sorting Recursion Pointers Character and Strings Structures Classes Inheritance Exceptions Templatess STL Modern C++ Misc Books ----

Move Semantics


Contents

Perfect Forwarding


File: foward1.cpp
#include <iostream>

using namespace std ;

class Object
{
 public:
  Object() = default;

  void SetName(const string &name) { name_ = move(name); }
  string GetName() const { return name_; }

 private:
  string name_;
};

void UseObject(Object& x1)
{
  cout << "calling UseObject(Object &)" << endl;
}

void UseObject(const Object& x1)
{
  cout << "calling UseObject(const Object &)" << endl;
}

void UseObject(Object&& x1)
{
  cout << "calling UseObject(Object &&)" << endl;
}

template <typename T>
void NotForwardToUseObject(T x)
{
  UseObject(x);
}

template <typename T>
void ForwardToUseObject(T &&x) {
  UseObject(static_cast<T &&>(x));
}

template <typename T>
void PerfectForwardToUseObject(T &&x) {
  UseObject(forward<T>(x));
}


int main()
{
  Object object;
  const Object const_object;
  UseObject(object);
  UseObject(const_object);
  UseObject(move(object));
  cout << "----" << endl;

   NotForwardToUseObject(object);
   NotForwardToUseObject(const_object);
   NotForwardToUseObject(move(object));

  cout << "----" << endl;
  ForwardToUseObject(object);
  ForwardToUseObject(const_object);
  ForwardToUseObject(move(object));
  cout << "----" << endl;

  PerfectForwardToUseObject(object);
  PerfectForwardToUseObject(const_object);
  PerfectForwardToUseObject(move(object));

}

$ rm a.exe ; g++ forward1.cpp ; ./a.exe
calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &&)
----
calling UseObject(Object &)
calling UseObject(Object &)
calling UseObject(Object &)
----
calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &&)
----
calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &&)

There are certain cases where we call a function that
can take a lvalue or rvalue reference.In the above file
we can see such a function:

void UseObject(Object& x1)
{
  cout << "calling UseObject(Object &)" << endl;
}

void UseObject(const Object& x1)
{
  cout << "calling UseObject(const Object &)" << endl;
}

void UseObject(Object&& x1)
{
  cout << "calling UseObject(Object &&)" << endl;
}

template 
void NotForwardToUseObject(T x)
{
  UseObject(x);
}

We want that the right "UseObject" should be called
when we call a common function such as "NotForwardToUseObject" .
We want the "UseObject" to be called for lvalue or rvalue references.
However we know that as long as we have a name it is a lvalue. To
preserve the concept of lvalue and rvalue we have the concept of
perfect forwarding.

template 
void PerfectForwardToUseObject(T&& x) {
  UseObject(forward(x));
}

The syntax is not very intuitive or logical but we define a
template function and the argument as "T&& x".
Now with the "forward" function we can preserve the lvalue or
rvalue of the argument.
Exercise
1)Explain the following program and output.
File: foward_ex1.cpp
#include <iostream>

using namespace std ;

class Object
{
 public:
  Object() = default;

  void SetName(const string &name) { name_ = move(name); }
  string GetName() const { return name_; }

 private:
  string name_;
};

void UseObject(Object& x1)
{
  cout << "calling UseObject(Object &)" << endl;
}

void UseObject(const Object& x1)
{
  cout << "calling UseObject(const Object &)" << endl;
}

void UseObject(Object&& x1)
{
  cout << "calling UseObject(Object &&)" << endl;
}

template <typename T>
void NotForwardToUseObject(T x)
{
  UseObject(x);
}

template <typename T>
void ForwardToUseObject(T &&x) {
  UseObject(static_cast<T &&>(x));
}

template <typename T>
void PerfectForwardToUseObject(T &&x) {
  //UseObject(forward<T>(x));
  UseObject(  x  );
}

template <typename T>
void PerfectForwardToUseObject1(T &&x) {
  UseObject(forward<T>(x));

}


int main()
{
  Object object;
  const Object const_object;

  cout << "----" << endl;

  PerfectForwardToUseObject(object);
  PerfectForwardToUseObject(const_object);
  PerfectForwardToUseObject(move(object));

  PerfectForwardToUseObject1(  Object()  );
  cout << "----" << endl;

}

$ g++ forward_ex1.cpp ; ./a.exe
----
calling UseObject(Object &)
calling UseObject(const Object &)
calling UseObject(Object &)
calling UseObject(Object &&)
----