| |
| [section In-Place Factories] |
| |
| One of the typical problems with wrappers and containers is that their |
| interfaces usually provide an operation to initialize or assign the |
| contained object as a copy of some other object. This not only requires the |
| underlying type to be __COPY_CONSTRUCTIBLE__, but also requires the existence of |
| a fully constructed object, often temporary, just to follow the copy from: |
| |
| struct X |
| { |
| X ( int, std::string ) ; |
| } ; |
| |
| class W |
| { |
| X wrapped_ ; |
| |
| public: |
| |
| W ( X const& x ) : wrapped_(x) {} |
| } ; |
| |
| void foo() |
| { |
| // Temporary object created. |
| W ( X(123,"hello") ) ; |
| } |
| |
| A solution to this problem is to support direct construction of the |
| contained object right in the container's storage. |
| In this scheme, the user only needs to supply the arguments to the |
| constructor to use in the wrapped object construction. |
| |
| class W |
| { |
| X wrapped_ ; |
| |
| public: |
| |
| W ( X const& x ) : wrapped_(x) {} |
| W ( int a0, std::string a1) : wrapped_(a0,a1) {} |
| } ; |
| |
| void foo() |
| { |
| // Wrapped object constructed in-place |
| // No temporary created. |
| W (123,"hello") ; |
| } |
| |
| A limitation of this method is that it doesn't scale well to wrapped |
| objects with multiple constructors nor to generic code were the constructor |
| overloads are unknown. |
| |
| The solution presented in this library is the family of [*InPlaceFactories] |
| and [*TypedInPlaceFactories]. |
| These factories are a family of classes which encapsulate an increasing |
| number of arbitrary constructor parameters and supply a method to construct |
| an object of a given type using those parameters at an address specified by |
| the user via placement new. |
| |
| For example, one member of this family looks like: |
| |
| template<class T,class A0, class A1> |
| class TypedInPlaceFactory2 |
| { |
| A0 m_a0 ; A1 m_a1 ; |
| |
| public: |
| |
| TypedInPlaceFactory2( A0 const& a0, A1 const& a1 ) : m_a0(a0), m_a1(a1) {} |
| |
| void construct ( void* p ) { new (p) T(m_a0,m_a1) ; } |
| } ; |
| |
| A wrapper class aware of this can use it as: |
| |
| class W |
| { |
| X wrapped_ ; |
| |
| public: |
| |
| W ( X const& x ) : wrapped_(x) {} |
| W ( TypedInPlaceFactory2 const& fac ) { fac.construct(&wrapped_) ; } |
| } ; |
| |
| void foo() |
| { |
| // Wrapped object constructed in-place via a TypedInPlaceFactory. |
| // No temporary created. |
| W ( TypedInPlaceFactory2<X,int,std::string>(123,"hello")) ; |
| } |
| |
| The factories are divided in two groups: |
| |
| * [_TypedInPlaceFactories]: those which take the target type as a primary |
| template parameter. |
| * [_InPlaceFactories]: those with a template `construct(void*)` member |
| function taking the target type. |
| |
| Within each group, all the family members differ only in the number of |
| parameters allowed. |
| |
| This library provides an overloaded set of helper template functions to |
| construct these factories without requiring unnecessary template parameters: |
| |
| template<class A0,...,class AN> |
| InPlaceFactoryN <A0,...,AN> in_place ( A0 const& a0, ..., AN const& aN) ; |
| |
| template<class T,class A0,...,class AN> |
| TypedInPlaceFactoryN <T,A0,...,AN> in_place ( T const& a0, A0 const& a0, ..., AN const& aN) ; |
| |
| In-place factories can be used generically by the wrapper and user as follows: |
| |
| class W |
| { |
| X wrapped_ ; |
| |
| public: |
| |
| W ( X const& x ) : wrapped_(x) {} |
| |
| template< class InPlaceFactory > |
| W ( InPlaceFactory const& fac ) { fac.template <X>construct(&wrapped_) ; } |
| |
| } ; |
| |
| void foo() |
| { |
| // Wrapped object constructed in-place via a InPlaceFactory. |
| // No temporary created. |
| W ( in_place(123,"hello") ) ; |
| } |
| |
| The factories are implemented in the headers: __IN_PLACE_FACTORY_HPP__ and __TYPED_IN_PLACE_FACTORY_HPP__ |
| |
| [endsect] |