...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
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.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.