コードを単体テストするとき、遅かれ早かれテストデータの問題が生じます。 そして、ある場合には少数のハードワイヤード変数で十分であれば、他の場合には、大規模でランダムなデータが必要になります。 制御された世界では、カスタムタイプを生成するのに問題はありません(同じAutofixtureを使用します)が、C ++の世界はしばしば痛みと苦痛を引き起こします(そうでない場合は修正してください)。 少し前に、私は素晴らしいboost :: diライブラリに精通し、その影響を受けて、C ++プログラマがランダムな値で詰まったカスタムデータ型を生成できるライブラリの概念が熟し始めました。これは予備的な説明を必要としません。 次のようになりました:
struct dummy_member{ float a; int b; }; struct dummy{ explicit dummy(dummy_member val, std::string c) : val_(val), c_(c) {} private: dummy_member val_; std::string c_; }; int main(int argc, char* argv){ auto d = datagen::random<dummy>(); return 0; }
→ コードにリンクします 。 ヘッダーのみのライブラリ、C ++ 14。 猫に興味がある人はみんな聞いてみてください。
主なライブラリ機能
- 組み込み型の生成
- ユーザータイプの生成(==非組み込み)
- 生成された値のセットのリミッター
インライン型生成
組み込み型(char、wchar_tなど)の生成は当然サポートされています。 この場合、整数型は単にビットのセットとして生成され、floatとdoubleはランダムな整数(それぞれ、int32_tとint64_t)と-1から1の範囲のランダムな値の合計として生成されます。ブール値を生成するには、2つのランダムな整数の比較が使用されます。
std::cout << "The answer to the question of everything is:" << datagen::random<int>() << std::endl;
カスタムタイプの生成。
カスタムタイプを生成するために、boost :: di(その作成者に感謝)と同じアイデアが使用されました。つまり、普遍的な型any_typeを記述する可能性があります。 LITTLEテンプレートを追加すると、次のツールを使用してカスタムタイプを生成することが判明しました。
- ユーザー定義の生成アルゴリズム。
- 最大数のパラメーターを持つパブリックコンストラクターに基づく生成。 すべてが記事の冒頭の例のようになります(
struct dymmy
)。 - {}-初期化に基づいた生成。 すべてが最初の例(
struct dummy_member
)と同じです。
ユーザー定義の手順に基づいてオブジェクトを生成するには、テンプレートを部分的または完全に特化する必要があります
template<> struct datagen::value_generation_algorithm<TType> { TType get_random(random_source_base&); };
これにより、このクラスの一部の型生成パラメーターメンバーを作成する機能が追加され、型生成に影響を与えることができます。 たとえば、std行生成アルゴリズムは次のようになります。
namespace datagen{ template <class CharType, class Traits, class Allocator> struct value_generation_algorithm<std::basic_string<CharType, Traits, Allocator>>{ using string_t = std::basic_string<CharType, Traits, Allocator>; string_t get_random(random_source_base& r_source){...}; size_t min_size{0}; size_t max_size{30}; std::basic_string<CharType> alphabet{"abcd...6789"}; }; }
生成された値のセットのリミッター
ライブラリは、生成された値のリミッターをサポートします。例:
std::cout << "The answer to the question of everything is:" << random<int>(between(42,42)) << std::endl;
リミッターには次の2種類があります。
- 生成アルゴリズムのリミッター。 彼らの助けを借りて、
value_generation_algorithm<T>
クラスのパラメーター値を変更できます。 - すでに生成された値へのリミッター(むしろ修正子)。
この場合、 2つの方法で使用できます 。
- 上記の例のように、それらをパラメーターとしてランダム関数に渡します。 この場合、それらは現在のアルゴリズム/値にのみ適用されます。
-
scoped_limit
基づいてscoped_limit
を作成scoped_limit
、それを一連の型に適用します。 その後、scoped_limitの有効期間中、生成されたタイプツリーの深さ全体に対して、指定されたすべてのタイプにリミッターが適用されます。
カスタム区切り文字を作成するには、区切り文字構造/クラスを宣言し、一方または両方の機能を実装する必要があります。
struct dummy_algorithm_limit{}; struct dummy_value_limit{}; namespace datagen{ namespace limits { void adjust_algorithm(random_source_base&, dummy_algorithm_limit const& l, value_generation_algorithm<dummy>& a){ // dummy } void adjust_value(random_source_base&, dummy_value_limit const& l, dummy& a){ // dummy } } }
制限は次の順序で適用されます。
- アルゴリズムのscoped_limit
- アルゴリズムごとのパラメトリックリミッター
これがオブジェクトツリーの生成です - 値のscoped_limit
- 値のパラメトリックリミッター
一般的な情報
ライブラリのエントロピーのソースは、 <random>
を使用するrandom_source_implクラスです。 ただし、コンパイル段階でrandom_source_instance<int>
構造の特殊化を提供することにより、これをオーバーライドできます。
今日、stlからの次のコンテナの生成が実装されています(実際に作業する必要があるもの)。
- std ::配列
- std ::マップ
- std ::セット
- std ::文字列
- std ::ベクトル
ブーストのタイプのペア:
- boost :: asio :: ip ::アドレス(v4、v6)
- ブースト::オプション
- ブースト:: posix_time :: ptime
- ブースト:: posix_time :: time_duration
それらのリミッター:
- だけでなく、組み込み型の
- より大きい、より小さい、奇数、偶数
- container_size :: between、container_size :: less_thanなど
- アルファベット:: contains_of、アルファベット:: does_not_contain
msvc-14.0コンパイラでテストされ、c ++ 14が必要です。 残念ながら、gccの動作は少し異なります。その結果、ライブラリのコードはmingw(gcc-6.3.0)でコンパイルされませんでしたが、それと絶えず接触している人はすぐに修正できると思います。
ライブラリはパブリックドメインにあります 。 新しいタイプのアイデアと実装は大歓迎です。