これは長い投稿なので、一番上に唯一の質問を書きたいと思います:
それ自体はアロケーターを使用しないカスタム コンテナーの「アロケーター拡張」コンストラクターを実装する必要があるようですが、これをバリアント型であり、許可された型が std:: map だけでなく、アロケーターを必要としない型、たとえばブール値。
一人では、これを達成する方法がわかりません。
助けていただければ幸いです。;)
「カスタム コンテナー」はvalue
、JSON データ構造の表現の実装であるクラス テンプレートです。
クラス テンプレートvalue
は、判別共用体の薄いラッパーです: クラス テンプレートvariant
(ブースト バリアントに似ています)。このバリアントで許可される型は、JSON 型の Object、Array、String、Number Boolean、および Null を表します。
クラス テンプレートには、基本的に JSON 型の実装方法を定義value
する可変個引数テンプレート テンプレート パラメーター パックがあります。Policies
デフォルトでは、JSON 型はstd::map
(オブジェクトの場合)、std::vector
(配列の場合)、std::string (JSON データ文字列の場合)、および残りの JSON 型を表すいくつかのカスタム クラスで実装されます。
で定義された type-machineryvalue
を使用して、指定されたおよびそれ自体に関してコンテナー型の再帰型定義を作成します。(バリアント クラスは、たとえば std::map または std::vector を使用する場合、JSON コンテナーの実装に「再帰ラッパー」を使用する必要はありません)。つまり、この型機構はJSON型を表すために使用される実際の型を作成します。(はい、型が生成される現時点では実際には不完全です)。Policies
value
std::vector
value_type
value
std::map
mapped_type
value
value
クラス テンプレートvalue
は基本的に次のようになります (大幅に簡略化されています)。
template <template <typename, typename> class... Policies>
class value
{
typedef json::Null null_type;
typedef json::Boolean boolean_type;
typedef typename <typegenerator>::type float_number_type;
typedef typename <typegenerator>::type integral_number_type;
typedef typename <typegenerator>::type string_type;
typedef typename <typegenerator>::type object_type;
typedef typename <typegenerator>::type array_type;
typedef variant<
null_type
, boolean_type
, float_number_type
, integral_number_type
, string_type
, object_type
, array_type
> variant_type;
public:
...
private:
variant_type value_;
};
value
コンストラクター、割り当て、アクセサー、コンパレーターなどの通常のサスペクトを実装します。また、バリアントの特定の実装タイプを引数リストで構築できるように、転送コンストラクターも実装します。
typegeneratorは基本的に関連する実装ポリシーを見つけて使用し、見つからない場合を除き、デフォルトの実装ポリシーを使用します (これについてはここでは詳しく説明しませんが、不明な点がある場合は質問してください)。
たとえば、array_type は次のようになります。object_type は次
std::vector<value, std::allocator<value>>
のようになります。
std::map<std::string, value, std::less<std::string>, std::allocator<std::pair<const std::string, value>>>
これまでのところ、これは意図したとおりに機能します。
ここでのアイデアは、ユーザーが「コンテナ」内のすべての割り当てとすべての構築に使用されるカスタム アロケータvalue
を指定できるようにすることです。たとえば、アリーナ アロケータです。
そのために、テンプレート パラメータをvalue
次のように拡張しました。
template <
typename A = std::allocator<void>,
template <typename, typename> class... Policies
>
class value ...
また、適切な場合に scoped_allocator_adaptor を使用するために、型の機械を適合させました。
テンプレート パラメータA
は-のallocator_typevalue
ではなく、適切な実装型を生成するために型機械で使用されるだけであることに注意してください。つまり、組み込みallocator_type
にはvalue
- はありませんが、実装型の allocator_type に影響します。
現在、ステートフルなカスタム アロケーターを使用する場合、これは途中までしか機能しません。より正確には、スコープ アロケータの伝播が正しく行われないことを除けば、動作します。例えば:
id
プロパティ、整数を持つステートフルなカスタム アロケータがあるとします。デフォルトで構築することはできません。
typedef test::custom_allocator<void> allocator_t;
typedef json::value<allocator_t> Value;
typedef typename Value::string_type String;
typedef Value::array_type Array;
allocator_t a1(1);
allocator_t a2(2);
// Create an Array using allocator a1:
Array array1(a1);
EXPECT_EQ(a1, array1.get_allocator());
// Create a value whose impl-type is a String which uses allocator a2:
Value v1("abc",a2);
// Insert via copy-ctor:
array1.push_back(v1);
// We expect, array1 used allocator a1 in order to construct internal copy of value v1 (containing a string):
EXPECT_EQ(a1, array1.back().get<String>().get_allocator());
--> FAILS !!
理由は、array1 が値 v1 のコピーを介してそのアロケーター メンバー (a1) を現在の imp 型である文字列の実際のコピーに伝達しないようです。
おそらくこれは、値の「アロケーター拡張」コンストラクターを介して実現できますが、それ自体はアロケーターを使用しませんが、必要に応じて適切に「伝播」する必要があります。
しかし、どうすればこれを達成できますか?
編集:型生成の一部を明らかにする:
「ポリシー」は、最初のパラメーターが value_type (この場合はvalue
) であり、2 番目のパラメーターがアロケーターの型であるテンプレート テンプレート パラメーターです。「ポリシー」は、JSON 型 (配列など) を値型とアロケータ型に関してどのように実装するかを定義します。
たとえば、JSON 配列の場合:
template <typename Value, typename Allocator>
struct default_array_policy : array_tag
{
private:
typedef Value value_type;
typedef typename Allocator::template rebind<value_type>::other value_type_allocator;
typedef GetScopedAllocator<value_type_allocator> allocator_type;
public:
typedef std::vector<value_type, allocator_type> type;
};
は次のようにGetScopedAllocator
定義されます。
template <typename Allocator>
using GetScopedAllocator = typename std::conditional<
std::is_empty<Allocator>::value,
Allocator,
std::scoped_allocator_adaptor<Allocator>
>::type;