emplace_back でも uniform initialization したい
なんかモヤモヤしたのでアロケータを自作して対応してみました。
アロケータ本体の実装はここら辺のコードを丸パクリ。
[ソース]
#include <vector> #include <string> #include <iostream> #include <limits> template <class T> class uniform_initialization_allocator; template<> class uniform_initialization_allocator<void> { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef void* pointer; typedef const void* const_pointer; typedef void value_type; template<typename _Tp1> struct rebind { typedef uniform_initialization_allocator<_Tp1> other; }; }; template <class T> struct uniform_initialization_allocator{ typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template <class U> struct rebind { typedef uniform_initialization_allocator<U> other; }; uniform_initialization_allocator() noexcept{} uniform_initialization_allocator(const uniform_initialization_allocator&) noexcept{} template <class U> uniform_initialization_allocator(const uniform_initialization_allocator<U>&) noexcept{} // デストラクタ ~uniform_initialization_allocator() noexcept{} // メモリを割り当てる pointer allocate(size_type num, uniform_initialization_allocator<void>::const_pointer hint = 0){ return (pointer)( ::operator new( num * sizeof(T) ) ); } pointer address(reference value) const { return &value; } const_pointer address(const_reference value) const { return &value; } size_type max_size() const noexcept { return std::numeric_limits<size_t>::max() / sizeof(T); } void deallocate(pointer p, size_type num) { ::operator delete( (void*)p ); } void destroy(pointer p) { p->~T(); } // 割当て済みの領域を初期化する void construct(pointer p, const T& value) { new( (void*)p ) T(value); } void construct(pointer p, T& value) { new( (void*)p ) T(value); } void construct(pointer p, T&& value) { new( (void*)p ) T(std::move(value)); } template<typename Up, typename... Args> void construct(Up* p, Args&&... args){ ::new((void *)p) Up{ std::forward<Args>(args)... }; } }; template <class T1, class T2> bool operator ==(const uniform_initialization_allocator<T1>&, const uniform_initialization_allocator<T2>&){ return true; } template <class T1, class T2> bool operator !=(const uniform_initialization_allocator<T1>&, const uniform_initialization_allocator<T2>&){ return false; } struct X{ int a; double b; std::string c; }; int main(){ std::vector<X, ::uniform_initialization_allocator<X>> xs; xs.emplace_back(42, 3.14, "homu"); std::cout << xs[0].a << std::endl; std::cout << xs[0].b << std::endl; std::cout << xs[0].c << std::endl; return 0; }
[出力]
42 3.14 homu
長々と書いてありますが、実際に実装すべき部分は uniform initialization で初期化するようにした construct メンバ関数だけですね。
アロケータで対応できるのはいいですね。