web-dev-qa-db-ja.com

C ++クラスの特性を追跡する方法は?

regular typesvalue semantics のファンとして、クラスがより規則的になり、非多態性になることを望んでいます。スローしない操作のファンとして、私はnoexceptである操作に熱心です。また、コンパイラーによって実際に生成されている特殊なメンバー関数の確認にも感謝します。そして、これらが関連付けられているコードと一緒にこれらのものを追跡したいと思います。

C++は <type_traits> ヘッダーファイルを提供します。このヘッダーファイルは、このような品質をチェックするためのクラスを提供し、次のような単体テストコードでそれらを利用するのを楽しんでいることがわかりました。

TEST(MyClass, Traits)
{      
    EXPECT_TRUE(std::is_constructible< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_constructible< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_constructible< MyClass >::value);

    EXPECT_TRUE(std::is_copy_constructible< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_copy_constructible< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_copy_constructible< MyClass >::value);

    EXPECT_TRUE(std::is_move_constructible< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_move_constructible< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_move_constructible< MyClass >::value);

    EXPECT_TRUE(std::is_copy_assignable< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_copy_assignable< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_copy_assignable< MyClass >::value);

    EXPECT_TRUE(std::is_move_assignable< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_move_assignable< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_move_assignable< MyClass >::value);

    EXPECT_TRUE(std::is_destructible< MyClass >::value);
    EXPECT_TRUE(std::is_nothrow_destructible< MyClass >::value);
    EXPECT_FALSE(std::is_trivially_destructible< MyClass >::value);

    EXPECT_TRUE(!std::is_polymorphic< MyClass >::value);
}

私のソースコードリビジョンシステムにも入る単体テストコードとして、これにはMyClassにコミットされるコードとともにこれらの品質を追跡できるという利点があります。 gamification クラスがこれらの品質をより多く発揮するのを見るのも好きです-これはこのようなコードを使用して行います。

しかし、私はこれを達成するために、多くの落とし穴なしでより多くの利点をもたらす他の方法があるのだろうか?

このテクニックに関して私が抱えているいくつかの懸念事項を次に示します。

  1. これらは単体テストとして受け入れられますか?彼らは私にとってはそうですが、他の人にとってはそうでしょうか? ウィキペディアが提供する単体テストの定義 はこれを修飾するのに十分主観的であるように見えますが、私はここで他の人がどれだけ広く同意するか心配しています。
  2. たとえばstatic_assertを使用して、クラスのコード自体などの他の場所でこれらの品質を追跡する方が良いでしょうか?これは、(他のソフトウェア開発者がこれを単体テストとして受け入れるかどうかではなく)それらがより良い場所であるかどうかに現在焦点を当てている最後の懸念とは異なります。示されているような単体テストコードではなくstatic_assertを介してクラスのコードでこれらの品質を追跡することは、これらの品質の重要性の高さのように見えます。よりパフォーマンスが重要なクラスでは、その方向性は理にかなっています。私はまた、これらの重要度を(テストの失敗やビルドの失敗の代わりに)単なる警告またはメッセージにすることよりも重要度を下げる必要があるという見方も認識しています。
  3. スケーラビリティの欠如。それは必要以上に定型コードですか?これは、このようなテストを作成するための簡単なコピーアンドペースト操作ですが、グローバルアップデートには適していません。可能な限りこれを抽象化して、更新できる場所が1か所になるようにしたいと思います。これを、これらのチェックを組み合わせてテンプレートパラメーターとして型を取得するテンプレート関数に変換することを検討しました。しかし、どのようにして真の値と偽の値を追跡しますか?これは出力レポートを生成する可能性がありますが、ローカル行番号を使用してEXPECT_*コンテキストに解析するのは面倒です。その間、マクロ関数は単体テストのコンテキストで評価されますが、マルチステートメントマクロ関数は、1つのソースコード行(マクロの呼び出し元の行)としてすべて表示されます。また、これらのチェックの通常、nothrow、およびtrivially形式を組み合わせて、1つの行のチェックに入れ、パラメーターを使用して、これらのいずれをポジティブに適用するかを示します。しかし、このパターンほど満足できるものはまだありません。
5
Louis Langholtz
  1. これらは単体テストとして受け入れられますか?

いいえ。これらは受け入れ可能な単体テストではありません。単体テストではimplementationではなくbehaviourをチェックする必要があります。あなたが持っているユニットテストはMyClassの動作をチェックしていません。

私が別の開発者であり、ソフトウェアスイートの通常の型を本当に気にしていないとします。何らかの理由で、コピーコンストラクターを削除したいとします。コードはコンパイルされますが、突然この単体テストが失敗します。私は今何をしますか?おそらく単体テストを削除して続行してください。そして、もし私が新しいクラスを書いたら、これらのテストを追加することを一瞬も考えません。

  1. たとえばstatic_assertを使用して、クラスのコード自体などの他の場所でこれらの品質を追跡する方が良いでしょうか?

確かに、static_assertは単体テストよりも優れたソリューションです(それが実装できる場合でも)。しかし、それはまだ役に立たないと思います。部分的には単体テストと同じ理由で。チームの別の開発者がそれらを追加しますか?おそらく、毎回すべてのアサーションをコピーするか、それらを生成する醜いマクロを作成することになります。

  1. スケーラビリティの欠如。それは必要以上に定型コードですか?

最も深刻な問題を特定しました。また、コード標準の何かを変更したい場合、すべてのクラスだけでなく、すべてのテストを更新するか、コピーしたことをアサートする必要があります。待って、私はコード標準に言及しましたか?はい、これはあなたのコード標準の一部であるべきだと思います。チームは通常、コーディング方法に関するコード標準を定義します。これはコードスタイル(明らかに同意する必要がある)だけでなく、ゼロの規則に従う、保護されたメンバー変数を使用しない、クラスを通常の型として動作させるなどのことも行います。次に、他の開発者がこれらのコード標準への準拠をチェックするレビューシステムがあります。はい、人はすり抜ける可能性がありますが、テストとアサートを行わずにレビューしないと、保証もありません。

3
Bernhard

これらの特性が型のインターフェースの一部である場合、理想的には、その型の宣言の近くで表明する必要があります。 compilationは(テストだけでなく)失敗するため、static_assertはそのための理想的な方法です。

一般に、テストは、例によってプログラムの特定のプロパティをチェックするのに役立ちます。彼らは通常、プログラムにバグがないことを示すことはできませんが、バグが存在する場合はバグを見つけるのに役立ちます。対照的に、型システムは正確性のプロパティの自動証明を提供します。型システムは(単なるシナリオの例ではなく)証明であるため、可能な場合は通常、型システムレベルのチェックを使用することをお勧めします。ここで、タイプ特性はタイプシステムレベルのプロパティであり、ランタイムプロパティではありません。単体テストスイートの一部としてそれらをチェックすることは間違っていませんが、混乱を招きます。

2
amon