Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Constructor Forwarding

Consider writing a generic factory function that returns an object for a newly constructed generic type. Factory functions such as this are valuable for encapsulating and localizing the allocation of resources. Obviously, the factory function must accept exactly the same sets of arguments as the constructors of the type of objects constructed:

template<class T> T* factory_new()
{  return new T();  }

template<class T> T* factory_new(a1)
{  return new T(a1);  }

template<class T> T* factory_new(a1, a2)
{  return new T(a1, a2);  }

Unfortunately, in C++03 the much bigger issue with this approach is that the N-argument case would require 2^N overloads, immediately discounting this as a general solution. Fortunately, most constructors take arguments by value, by const-reference or by rvalue reference. If these limitations are accepted, the forwarding emulation of a N-argument case requires just N overloads. This library makes this emulation easy with the help of BOOST_FWD_REF and boost::forward:

#include <boost/move/utility_core.hpp>
#include <iostream>

class copyable_only_tester
{
   public:
   copyable_only_tester()
   {  std::cout << "copyable_only_tester()" << std::endl;   }

   copyable_only_tester(const copyable_only_tester&)
   {  std::cout << "copyable_only_tester(const copyable_only_tester&)" << std::endl;   }

   copyable_only_tester(int)
   {  std::cout << "copyable_only_tester(int)" << std::endl;   }

   copyable_only_tester(int, double)
   {  std::cout << "copyable_only_tester(int, double)" << std::endl;   }
};

class copyable_movable_tester
{
   // move semantics
   BOOST_COPYABLE_AND_MOVABLE(copyable_movable_tester)
   public:

   copyable_movable_tester()
   {  std::cout << "copyable_movable_tester()" << std::endl;   }

   copyable_movable_tester(int)
   {  std::cout << "copyable_movable_tester(int)" << std::endl;   }

   copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester))
   {  std::cout << "copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester))" << std::endl;   }

   copyable_movable_tester(const copyable_movable_tester &)
   {  std::cout << "copyable_movable_tester(const copyable_movable_tester &)" << std::endl;   }

   copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester))
   {  std::cout << "copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester))" << std::endl;   }

   copyable_movable_tester &operator=(BOOST_RV_REF(copyable_movable_tester))
   {  std::cout << "copyable_movable_tester & operator=(BOOST_RV_REF(copyable_movable_tester))" << std::endl;
      return *this;  }

   copyable_movable_tester &operator=(BOOST_COPY_ASSIGN_REF(copyable_movable_tester))
   {  std::cout << "copyable_movable_tester & operator=(BOOST_COPY_ASSIGN_REF(copyable_movable_tester))" << std::endl;
      return *this;  }
};

//1 argument
template<class MaybeMovable, class MaybeRv>
void function_construct(BOOST_FWD_REF(MaybeRv) x)
{  MaybeMovable m(boost::forward<MaybeRv>(x));   }

//2 argument
template<class MaybeMovable, class MaybeRv, class MaybeRv2>
void function_construct(BOOST_FWD_REF(MaybeRv) x, BOOST_FWD_REF(MaybeRv2) x2)
{  MaybeMovable m(boost::forward<MaybeRv>(x), boost::forward<MaybeRv2>(x2));  }

int main()
{
   copyable_movable_tester m;
   //move constructor
   function_construct<copyable_movable_tester>(boost::move(m));
   //copy constructor
   function_construct<copyable_movable_tester>(copyable_movable_tester());
   //two rvalue constructor
   function_construct<copyable_movable_tester>(boost::move(m), boost::move(m));

   copyable_only_tester nm;
   //copy constructor (copyable_only_tester has no move ctor.)
   function_construct<copyable_only_tester>(boost::move(nm));
   //copy constructor
   function_construct<copyable_only_tester>(nm);
   //int constructor
   function_construct<copyable_only_tester>(int(0));
   //int, double constructor
   function_construct<copyable_only_tester>(int(0), double(0.0));

   //Output is:
   //copyable_movable_tester()
   //copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester))
   //copyable_movable_tester()
   //copyable_movable_tester(const copyable_movable_tester &)
   //copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester))
   //copyable_only_tester()
   //copyable_only_tester(const copyable_only_tester&)
   //copyable_only_tester(const copyable_only_tester&)
   //copyable_only_tester(int)
   //copyable_only_tester(int, double)
   return 0;
}

Constructor forwarding comes in handy to implement placement insertion in containers with just N overloads if the implementor accepts the limitations of this type of forwarding for C++03 compilers. In compilers with rvalue references perfect forwarding is achieved.


PrevUpHomeNext