memory_resource には std::pair に対しての処理が入っていなかったですね。
おんや? これで良いんだべ?
とか疑問に思った読者もいるでしょう。
はい、std::pair 引数の受付は memory_resource ではなく polymorphic_allocator によって、実装されています。
この 2 つのヘッダーが良くも悪くも、今の実装状況ということになるかと思います。
uses_allocator.h (https://github.com/MacKomatsu/gcc/blob/master/libstdc%2B%2B-v3/include/bits/uses_allocator.h).
55 template<typename _Tp, typename _Alloc, typename = __void_t<>> 56 struct __uses_allocator_helper 57 : false_type { }; 58 59 template<typename _Tp, typename _Alloc> 60 struct __uses_allocator_helper<_Tp, _Alloc, 61 __void_t<typename _Tp::allocator_type>> 62 : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type 63 { }; 64 65 /// [allocator.uses.trait] 66 template<typename _Tp, typename _Alloc> 67 struct uses_allocator 68 : __uses_allocator_helper<_Tp, _Alloc>::type 69 { }; 70 71 struct __uses_alloc_base { }; 72 73 struct __uses_alloc0 : __uses_alloc_base 74 { 75 struct _Sink { void operator=(const void*) { } } _M_a; 76 }; 77 78 template<typename _Alloc> 79 struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; }; 80 81 template<typename _Alloc> 82 struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; }; 83 84 template<bool, typename _Tp, typename _Alloc, typename... _Args> 85 struct __uses_alloc; 86 87 template<typename _Tp, typename _Alloc, typename... _Args> 88 struct __uses_alloc<true, _Tp, _Alloc, _Args...> 89 : conditional< 90 is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value, 91 __uses_alloc1<_Alloc>, 92 __uses_alloc2<_Alloc>>::type 93 { 94 static_assert(__or_< 95 is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>, 96 is_constructible<_Tp, _Args..., _Alloc>>::value, "construction with" 97 " an allocator must be possible if uses_allocator is true"); 98 }; 99 100 template<typename _Tp, typename _Alloc, typename... _Args> 101 struct __uses_alloc<false, _Tp, _Alloc, _Args...> 102 : __uses_alloc0 { }; 103 104 template<typename _Tp, typename _Alloc, typename... _Args> 105 using __uses_alloc_t = 106 __uses_alloc<uses_allocator<_Tp, _Alloc>::value, _Tp, _Alloc, _Args...>; 107 108 template<typename _Tp, typename _Alloc, typename... _Args> 109 inline __uses_alloc_t<_Tp, _Alloc, _Args...> 110 __use_alloc(const _Alloc& __a) 111 { 112 __uses_alloc_t<_Tp, _Alloc, _Args...> __ret; 113 __ret._M_a = std::__addressof(__a); 114 return __ret; 115 }
ポリモーフィックアロケーターのソースコードは以下の通りです。
polymorphic_allocator クラス (https://github.com/MacKomatsu/gcc/blob/master/libstdc%2B%2B-v3/include/experimental/memory_resource).
115 // 8.6 Class template polymorphic_allocator 116 template <class _Tp> 117 class polymorphic_allocator 118 { 119 using __uses_alloc1_ = __uses_alloc1<memory_resource*>; 120 using __uses_alloc2_ = __uses_alloc2<memory_resource*>; 121 122 template<typename _Tp1, typename... _Args> 123 void 124 _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) 125 { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } 126 127 template<typename _Tp1, typename... _Args> 128 void 129 _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&... __args) 130 { ::new(__p) _Tp1(allocator_arg, this->resource(), 131 std::forward<_Args>(__args)...); } 132 133 template<typename _Tp1, typename... _Args> 134 void 135 _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&... __args) 136 { ::new(__p) _Tp1(std::forward<_Args>(__args)..., 137 this->resource()); } 138 139 public: 140 using value_type = _Tp; 141 142 polymorphic_allocator() noexcept 143 : _M_resource(get_default_resource()) 144 { } 145 146 polymorphic_allocator(memory_resource* __r) 147 : _M_resource(__r) 148 { _GLIBCXX_DEBUG_ASSERT(__r); } 149 150 polymorphic_allocator(const polymorphic_allocator& __other) = default; 151 152 template <typename _Up> 153 polymorphic_allocator(const polymorphic_allocator<_Up>& 154 __other) noexcept 155 : _M_resource(__other.resource()) 156 { } 157 158 polymorphic_allocator& 159 operator=(const polymorphic_allocator& __rhs) = default; 160 161 _Tp* allocate(size_t __n) 162 { return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), 163 alignof(_Tp))); } 164 165 void deallocate(_Tp* __p, size_t __n) 166 { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } 167 168 template <typename _Tp1, typename... _Args> //used here 169 void construct(_Tp1* __p, _Args&&... __args) 170 { 171 memory_resource* const __resource = this->resource(); 172 auto __use_tag 173 = __use_alloc<_Tp1, memory_resource*, _Args...>(__resource); 174 _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); 175 } 176 177 // Specializations for pair using piecewise construction 178 template <typename _Tp1, typename _Tp2, 179 typename... _Args1, typename... _Args2> 180 void construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, 181 tuple<_Args1...> __x, 182 tuple<_Args2...> __y) 183 { 184 memory_resource* const __resource = this->resource(); 185 auto __x_use_tag = 186 __use_alloc<_Tp1, memory_resource*, _Args1...>(__resource); 187 auto __y_use_tag = 188 __use_alloc<_Tp2, memory_resource*, _Args2...>(__resource); 189 190 ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, 191 _M_construct_p(__x_use_tag, __x), 192 _M_construct_p(__y_use_tag, __y)); 193 } 194 195 template <typename _Tp1, typename _Tp2> 196 void construct(pair<_Tp1,_Tp2>* __p) 197 { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } 198 199 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 200 void construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y) 201 { this->construct(__p, piecewise_construct, 202 forward_as_tuple(std::forward<_Up>(__x)), 203 forward_as_tuple(std::forward<_Vp>(__y))); } 204 205 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 206 void construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr) 207 { this->construct(__p, piecewise_construct, forward_as_tuple(__pr.first), 208 forward_as_tuple(__pr.second)); } 209 210 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 211 void construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr) 212 { this->construct(__p, piecewise_construct, 213 forward_as_tuple(std::forward<_Up>(__pr.first)), 214 forward_as_tuple(std::forward<_Vp>(__pr.second))); } 215 216 template <typename _Up> 217 void destroy(_Up* __p) 218 { __p->~_Up(); } 219 220 // Return a default-constructed allocator (no allocator propagation) 221 polymorphic_allocator select_on_container_copy_construction() const 222 { return polymorphic_allocator(); } 223 224 memory_resource* resource() const 225 { return _M_resource; } 226 227 private: 228 template<typename _Tuple> 229 _Tuple&& 230 _M_construct_p(__uses_alloc0, _Tuple& __t) 231 { return std::move(__t); } 232 233 template<typename... _Args> 234 decltype(auto) 235 _M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t) 236 { return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)), 237 std::move(__t)); } 238 239 template<typename... _Args> 240 decltype(auto) 241 _M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t) 242 { return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); } 243 244 memory_resource* _M_resource; 245 };
はーいはい、これまでの本書の蓄積があれば、ソースの分かりみが深いはずです。
ですよね?
std::pair 対策もきっちりやっていますし、筆者のサンプルコードと違って非の打ち所の無い完璧なコードです。
他の pmr コンテナについては以下のような定義となると思いますが 2019 年の段階で使えるかは、まだ試していないので分かりませんね。
namespace pmr { template <class T> using list = std::list<T, std::pmr::polymorphic_allocator<T>>; } namespace pmr { template <class Key, class T, class Compare = std::less<Key>> using map = std::map<Key, T, Compare, std::pmr::polymorphic_allocator<std::pair<const Key,T>>> } namespace pmr { template <class Key, class Compare = std::less<Key>> using multiset = std::multiset<Key, Compare, std::pmr::polymorphic_allocator<Key>>; } namespace pmr { template <class Key, class Compare = std::less<Key>> using set = std::set<Key, Compare, std::pmr::polymorphic_allocator<Key>>; } namespace pmr { template <class Key, class T, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>> using unordered_map = std::unordered_map<Key, T, Hash, Pred, std::pmr::polymorphic_allocator<std::pair<const Key,T>>>; } namespace pmr { template <class Key, class T, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>> using unordered_multimap = std::unordered_multimap<Key, T, Hash, Pred, std::pmr::polymorphic_allocator<std::pair<const Key,T>>>; } namespace pmr { template <class Key, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>> using unordered_set = std::unordered_set<Key, Hash, Pred, std::pmr::polymorphic_allocator<Key>>; } namespace pmr { template <class Key, class Hash = std::hash<Key>, class Pred = std::equal_to<Key>> using unordered_multiset = std::unordered_multiset<Key, Hash, Pred, std::pmr::polymorphic_allocator<Key>> }
まだ実験的なものという理解なんで、これを使用しているコードを見る機会はあまり無いと思います。
Copyright 2018-2019, by Masaki Komatsu