Одна из типичных проблем с обертками и контейнерами заключается в том, что их интерфейсы обычно обеспечивают операцию инициализации или присвоения содержащегося объекта в качестве копии какого-либо другого объекта. Это не только требует, чтобы основной тип был<CopyConstructible
>, но также требует существования полностью построенного объекта, часто временного, просто чтобы следовать копии из:
struct X
{
X ( int, std::string ) ;
} ;
class W
{
X wrapped_ ;
public:
W ( X const& x ) : wrapped_(x) {}
} ;
void foo()
{
W ( X(123,"hello") ) ;
}
Решение этой проблемы заключается в поддержке непосредственного строительства содержащегося объекта прямо в контейнере. В этой схеме пользователю нужно только предоставить аргументы конструктору для использования в обернутой конструкции объекта.
class W
{
X wrapped_ ;
public:
W ( X const& x ) : wrapped_(x) {}
W ( int a0, std::string a1) : wrapped_(a0,a1) {}
} ;
void foo()
{
W (123,"hello") ;
}
Ограничение этого метода заключается в том, что он плохо масштабируется для обертывания объектов несколькими конструкторами, а также для общего кода, если перегрузки конструктора неизвестны.
Решение, представленное в этой библиотеке, является семейством.На фабрикахиТипизированные фабрики. Эти фабрики представляют собой семейство классов, которые инкапсулируют все большее число произвольных параметров конструктора и поставляют способ построения объекта заданного типа с использованием этих параметров по адресу, указанному пользователем посредством размещения нового.
Например, один из членов этой семьи выглядит так:
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) ; }
} ;
Класс обертки, знающий об этом, может использовать его в качестве:
class W
{
X wrapped_ ;
public:
W ( X const& x ) : wrapped_(x) {}
W ( TypedInPlaceFactory2 const& fac ) { fac.construct(&wrapped_) ; }
} ;
void foo()
{
W ( TypedInPlaceFactory2<X,int,std::string>(123,"hello")) ;
}
Фабрики делятся на две группы:
- TypedInPlaceFactories: те, которые принимают целевой тип в качестве основного параметра шаблона.
- На фабриках: Для тех, у кого есть шаблон<
construct(void*)
>, функция принимает целевой тип.
В рамках каждой группы все члены семьи отличаются только количеством разрешенных параметров.
Эта библиотека предоставляет перегруженный набор функций вспомогательных шаблонов для строительства этих фабрик без необходимости использования ненужных параметров шаблона:
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) ;
Заводы на месте могут использоваться оберткой и пользователем следующим образом:
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()
{
W ( in_place(123,"hello") ) ;
}
Заводы реализованы в заголовках:in_place_factory.hppиtyped_in_place_factory.hpp