Constructor Forwarding

| Home | Libraries | People | FAQ | More

## 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.