次のコードを検討してください。
#include <iostream>
#include <type_traits>
template <typename T>
struct A {
int val = 0;
template <class = typename std::enable_if<T::value>::type>
A(int n) : val(n) {};
A(...) { }
/* ... */
};
struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };
int main() {
A<YES> y(10);
A<NO> n;
std::cout << "YES: " << y.val << std::endl
<< "NO: " << n.val << std::endl;
}
Enable_ifを使用して、一部のタイプのコンストラクターA :: A(int)のみを選択的に定義します。他のすべてのタイプには、デフォルトコンストラクターA :: A(...)があります。これは、置換が失敗した場合のコンパイラーのデフォルトのケースです。しかし、これは私にとって意味がありますコンパイラ(gccバージョン4.9.0 20130714)はまだ文句を言っています
sfinae.cpp: 'struct A'のインスタンス化:sfinae.cpp:19:11:
ここから必要sfinae.cpp:9:5:エラー: 'type'という名前のタイプはありません
'struct std :: enable_if'
A(int n):val(n){};
このようなものはコンストラクターに可能ですか?これは別のコンストラクター(copy-constructorおよびmove-constructor)で可能ですか?
クラステンプレートをインスタンス化するときに値を解決する必要があるため、これは単一の既定のテンプレートパラメーターでは機能しないと思います。
コンストラクターテンプレートのインスタンス化の時点まで置換を延期する必要があります。 1つの方法は、テンプレートパラメーターをTにデフォルト設定し、コンストラクターに追加のダミーパラメーターを追加することです。
template<typename U = T>
A(int n, typename std::enable_if<U::value>::type* = 0) : val(n) { }
通常、これは匿名のデフォルト引数を使用して行われます:
A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {};
クラスのテンプレートパラメータをSFINAE outメソッドに使用することはできません。 SO 1つの方法は、intを置き換えるダミー型を追加することです。
#include <iostream>
#include <type_traits>
template <typename T>
struct A {
int val = 0;
template<typename Integer
,typename = typename std::enable_if<T::value && sizeof(Integer)>::type
>
A(Integer n) : val(n) {};
A(...) {}
/* ... */
};
struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };
int main() {
A<YES> y(10);
A<NO> n;
std::cout << "YES: " << y.val << std::endl
<< "NO: " << n.val << std::endl;
}
これは、メンバーテンプレートパラメーターを使用してコンストラクターをSFINAEするために機能しますが、テストは常にtrueであるため、チェックを汚染しません