namespace std {
template <class T, class Alloc>
struct uses_allocator;
template <class T, class Alloc>
inline constexpr bool uses_allocator_v = uses_allocator<T, Alloc>::value; // C++17 から
}
概要
型 T
が Alloc
型のアロケータオブジェクトを用いた uses-allocator 構築をする際に、実際にアロケータオブジェクトを使用するかを調べる。
このクラスが true_type
から派生する場合、以下のいずれかの構築が可能である:
T(allocator_arg, alloc, args...)
のように、第1引数にallocator_arg
、第2引数にAlloc
型のアロケータオブジェクトalloc
をとる構築。T(args..., alloc)
のように、最後の引数としてAlloc
型のアロケータオブジェクトalloc
をとる構築。
このクラスのデフォルト実装は、型 T
が public
なメンバ型 allocator_type
を持っており、その型が Alloc
から変換可能であれば true_type
から派生し、そうでなければ false_type
から派生する。
型 T
が Alloc
から変換可能なメンバ型 allocator_type
を持っていないが上記いずれかの構築が可能な場合は、true_type
から派生した本クラステンプレートの特殊化を提供することで、アロケータを用いた構築をサポートしていることを示すことが可能である。
uses-allocator 構築
「uses-allocator 構築」とは、型 T
のオブジェクト obj
を構築する際に、引数とアロケータを T
のコンストラクタに適切に引き渡すような構築方法である。
アロケータのオブジェクトを alloc
、型を Alloc
とし、引数列を v1, v2, ..., vN
、その型を V1, V2, ..., VN
とすると
-
T
がアロケータを利用しない場合(uses_allocator<T, Alloc>::value == false
かつ、is_constructible<T, V1, V2, ..., VN>::value == true
ならば)
obj(v1, v2, ..., vN);
の形でコンストラクタを呼び出す。 -
T
がアロケータを利用し、アロケータをコンストラクタ引数の先頭で受け取る場合(uses_allocator<T, Alloc>::value == true
かつ、is_constructible<T, allocator_arg_t, Alloc, V1, V2, ..., VN>::value == true
ならば)
obj(allocator_arg, alloc, v1, v2, ..., vN);
の形でコンストラクタを呼び出す。 -
T
がアロケータを利用し、アロケータをコンストラクタ引数の末尾で受け取る場合(uses_allocator<T, Alloc>::value == true
かつ、is_constructible<T, V1, V2, ..., VN, Alloc>::value == true
ならば)
obj(v1, v2, ..., vN, alloc);
の形でコンストラクタを呼び出す。 -
それ以外の場合、要求された構築はill-formedである。
すなわち、構築したい型がアロケータを利用するならば引数とアロケータを適切な順序でコンストラクタに与えて呼び出し、利用しないならば通常のコンストラクタ呼び出しを行うような構築方法である。
更に上記に加え C++20 以降では、構築する対象の型 T
が pair
の特殊化だった場合には、当該 pair
のそれぞれの要素に対して再帰的に上記の構築方法を適用することが規定された。
備考
- 本型トレイツは、主にスコープアロケータモデルを採用するアロケータで使用されることを意図している。
標準ライブラリでは、scoped_allocator_adaptor
、polymorphic_allocator
クラステンプレートで使用されている。 - 標準ライブラリで提供されるいくつかの型は本型トレイツの特殊化を提供している。(
tuple
、promise
、各種コンテナアダプタ等) pair
はtuple
と同列の機能と考えられるが、本型トレイツの特殊化を提供していない。このため、標準ライブラリで提供されるスコープアロケータモデルを採用したアロケータでは C++17 までは独自にpair
の各要素に対して uses-allocator 構築を適用している(ただし、ネストしたpair
の要素に対してはアロケータは伝播されない)。
スコープアロケータモデルを採用したアロケータを自作する場合には、同様の対応を行う方が良いだろう。
なお、C++20 でpair
に対する特殊対応を含めた uses-allocator 構築サポートのためのユーティリティ関数が追加されたため、以前に比べて容易に uses-allocator 構築への対応が可能となった。
例
#include <iostream>
#include <memory>
template <class T, class Allocator = std::allocator<T>>
struct X {
T x_;
Allocator alloc_;
public:
using allocator_type = Allocator;
X(std::allocator_arg_t, Allocator alloc, T x)
: alloc_(alloc), x_(x) {}
};
int main()
{
const bool result = std::uses_allocator<X<int>, std::allocator<int>>::value;
static_assert(result, "should be true");
}
#include <iostream>
#include <memory>
template <class T, class Allocator = std::allocator<T>>
struct X {
T x_;
Allocator alloc_;
public:
using allocator_type = Allocator;
X(std::allocator_arg_t, Allocator alloc, T x)
: alloc_(alloc), x_(x) {}
};
int main()
{
const bool result = std::uses_allocator<X<int>, std::allocator<int>>::value;
static_assert(result, "should be true");
出力
バージョン
言語
- C++11
処理系
- Clang: 3.0 ✅
- GCC: 4.6.4 ✅
- ICC: ??
- Visual C++: 2012 ✅, 2013 ✅
関連項目
scoped_allocator_adaptor
polymorphic_allocator
tuple
promise
uses_allocator_construction_args
make_obj_using_allocator
uninitialized_construct_using_allocator