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番目にかかります。なぜそれが機能するのですか?ここにはどのようなコンパイルルールがありますか?
つまり、テンプレートの特殊化ルールと関係があります。これらは関数のオーバーロードに似ていますが、型用です。
ここで、コンパイラーは、より一般的なタイプよりも、より特殊なタイプを優先します。
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つの特殊なパラメーターを備えたバージョンと比較してより一般的です。
最も一般的なケースを宣言するだけでもかまいません(つまり、テンプレートの一般的な形式は宣言されているだけで定義されていません)。実際に必要なケースにのみ特化しています。特殊化されていないすべてのケースでは、コンパイルエラーが発生し、特定のタイプのケースを特殊化するようにユーザーに求めます。
なぜそれが機能するのですか?ここにはどのようなコンパイルルールがありますか?
私は専門家ではありませんが、実践的な観点から説明しようと思います。
権利条項を使用したい...
と
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
で特殊化されたもの)を選択します。anchetype
はdouble
です。
For
typename std::conditional<true,int,double>::type a;
汎用バージョンのみが一致するため、type
はint
です。
ここで使用されているテンプレートメタプログラミングの主なルールのほとんどはSFINAEです(置換の失敗はエラーではありません)。この規則によれば、コンパイラが型を見つけられない場合、エラーをスローする代わりに、先に進み、型情報を提供できる将来のステートメントがあるかどうかを確認します。