![]() |
Home | Libraries | People | FAQ | More |
使用包裝器和容器的一個常見問題是,它們通常會有一個接口提供一個操作,將所含對像初始化或賦值為另一個對象的拷貝。這不僅要求底層的類型是 可複製構造的,而且還要求一個完全構造的對象,該對像通常是臨時的,僅用作複製的來源:
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") ; }
這種方法的限制在於,它不適用於帶有多個構造函數的被包裝對象,也不適用於對構造函數重載不知情的泛型代碼。
在本庫中,解決的方法是 InPlaceFactories 和 TypedInPlaceFactories 家族。這些工廠是一族類,這些類封裝了不同參數數量的構造函數參數,提供一個方法來構造給定類型的一個對象,構造時使用這些被封裝的參數,並通過 placement new 在用戶指定的地址進行構造。
例如,這個類族中的其中一個類如下:
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() { // 通過 TypedInPlaceFactory 就地構造被包裝對象。無需創建臨時對象。
W ( TypedInPlaceFactory2<X,int,std::string&rt(123,"hello")) ; }
這些工廠類被分為兩組:
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() { // 通過 InPlaceFactory 就地構造被包裝的對象。無需創建臨時對象。
W ( in_place(123,"hello") ) ; }
這些工廠類在頭文件 in_place_factory.hpp 和 typed_in_place_factory.hpp 中實現。