140 lines
3.8 KiB
Plaintext
140 lines
3.8 KiB
Plaintext
|
|
[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]
|