web-dev-qa-db-ja.com

std :: conditionalのしくみ

std::conditionalと呼ばれるこの小さなメタプログラミングの驚異が説明されています ここ 。同じ参考文献では、可能な実装は

template<bool B, class T, class F>
struct conditional { typedef T type; };

template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

したがって、コードで次のようなことを行う場合

typename std::conditional<true,int,double>::type a;

コンパイラは最初の定義に従い、私が次のようなことをすると

typename std::conditional<false,int,double>::type b

コンパイラは2番目にかかります。なぜそれが機能するのですか?ここにはどのようなコンパイルルールがありますか?

11
alcoforado

つまり、テンプレートの特殊化ルールと関係があります。これらは関数のオーバーロードに似ていますが、型用です。

ここで、コンパイラーは、より一般的なタイプよりも、より特殊なタイプを優先します。

template<bool B, class T, class F>
struct conditional { typedef T type; };

template<class T, class F>
struct conditional<false, T, F> { typedef F type; };

したがって、テンプレートのインスタンス化coditional<false, ...>がコンパイラによって検出されると、次のように検出されます。

  • 一般的なテンプレートtemplate<bool B, class T, class F> struct conditional
  • そのすべての専門分野:template<class T, class F> struct conditional<false, T, F>

その時点で、可能な限り多くの特殊化された引数に一致させようとし、最終的にfalseで特殊化を選択します。

たとえば、次のような別のバージョンを導入します。

template<class F>
struct conditional<false, int, F> { typedef int type; };

conditional<false, int, double>のようなテンプレートタイプをインスタンス化すると、特殊化が優先されます

template<class F> struct conditional<false, int, F>

template<class T, class F> struct conditional<false, T, F>これは、2つの特殊なパラメーターを備えたバージョンと比較してより一般的です。

この時点でのいくつかのトリック:

最も一般的なケースを宣言するだけでもかまいません(つまり、テンプレートの一般的な形式は宣言されているだけで定義されていません)。実際に必要なケースにのみ特化しています。特殊化されていないすべてのケースでは、コンパイルエラーが発生し、特定のタイプのケースを特殊化するようにユーザーに求めます。

8
ovanes

なぜそれが機能するのですか?ここにはどのようなコンパイルルールがありますか?

私は専門家ではありませんが、実践的な観点から説明しようと思います。

権利条項を使用したい...

template <bool B, class T, class F>
struct conditional { typedef T type; };

(しかし、C++ 11では、私は好みます

template <bool B, typename T, typename>
struct conditional { using type = T; };

)テンプレートを宣言します

template <bool, typename, typename>
struct conditional;

汎用(特殊ではない)バージョンを定義します。

template< class T, class F>
struct conditional<false, T, F> { typedef F type; };

(または、C++ 11では、

template <typename T, typename F>
struct conditional<false, T, F> { using type = F; };

conditionalの部分的な特殊化を定義します

クラス(または構造体)のテンプレート引数が2つ以上の定義に一致する場合、コンパイラーはより専門的なものを選択します。だから、

typename std::conditional<false,int,double>::type

クラスの両方の定義が一致するため、コンパイラーは特殊なもの(falseで特殊化されたもの)を選択します。anchetypedoubleです。

For

typename std::conditional<true,int,double>::type a;

汎用バージョンのみが一致するため、typeintです。

4
max66

ここで使用されているテンプレートメタプログラミングの主なルールのほとんどはSFINAEです(置換の失敗はエラーではありません)。この規則によれば、コンパイラが型を見つけられない場合、エラーをスローする代わりに、先に進み、型情報を提供できる将来のステートメントがあるかどうかを確認します。

0