なぜこれがgcc48とclang32でコンパイルされないのですか?
#include <type_traits>
template <int N>
struct S {
template<class T>
typename std::enable_if<N==1, int>::type
f(T t) {return 1;};
template<class T>
typename std::enable_if<N!=1, int>::type
f(T t) {return 2;};
};
int main() {
S<1> s1;
return s1.f(99);
}
GCCエラー:
/home/lvv/p/sto/test/t.cc:12:2: error: no type named ‘type’ in ‘struct enable_if<false, int>’
f(T t) {return 2;};
^
CLANGエラー:
/home/lvv/p/sto/test/t.cc:11:26: error: no type named 'type' in 'std::enable_if<false, int>'; 'enable_if' cannot be used to
disable this declaration
typename std::enable_if<N!=1, int>::type
^~~~
/home/lvv/p/sto/test/t.cc:16:7: note: in instantiation of template class 'S<1>' requested here
S<1> s1;
^
編集-ソリューション
Charles Salviaからの回答を受け入れましたが、実用的な理由から、提案された回避策(Nに特化)を使用できませんでした。私に役立つ他の回避策を見つけました。作るenable_if
依存するT
:
typename std::enable_if<(sizeof(T),N==1), int>::type
enable_if
関数テンプレートでテンプレートパラメータT
を使用しません。 struct S
に特定のテンプレートパラメータ値N
がある場合に特化したい場合は、クラステンプレートの特化を使用する必要があります。
template <int N, class Enable = void>
struct S { };
template <int N>
struct S<N, typename std::enable_if<N == 1>::type>
{
....
};
まあ、あなたが何をしたかったのかはわかりませんが、おそらくこのコードが役立つでしょう:
#include <iostream>
template <int N>
struct S {
template<class T=int>
typename std::enable_if<N==1, T>::type
f(T t) {return 1;}
template<class T=int>
typename std::enable_if<N!=1, T>::type
f(T t) {return 2;}
};
int main()
{
S<1> s1;
S<2> s2;
std::cout << s1.f(99) << " " << std::endl << s2.f(5);
}
これは1と2を出力します。
次のように、デフォルトのブールテンプレートパラメータを使用します。
template <int N>
struct S {
template<class T, bool EnableBool=true>
typename std::enable_if<N==1 && EnableBool, int>::type
f(T t) {return 1;};
template<class T, bool EnableBool=true>
typename std::enable_if<N!=1 && EnableBool, int>::type
f(T t) {return 2;};
};
std::enable_if
をこのように機能させるには、SFINAEを使用します。残念ながら、宣言した時点で
S<1> s1;
S<1>
のメンバー宣言をすべてインスタンス化します。 SFINAEは、S<1>
が不正な形式の構成要素である場合にのみ、この時点で機能します。そうではない。残念ながら、これには無効な関数が含まれているため、S<>
のインスタンス化は無効です。
このような場合、別のテンプレート構造体を使用する場合があります。
template <bool B>
struct f_functor {
template <typename T>
static int f(T t) { return 1; }
};
template <>
struct f_functor<false> {
template <typename T>
static int f(T t) { return 2; }
};
template <int N>
struct S {
template<class T>
typename int f(T t) { return f_functor<N==1>::f(t); }
};
この場合、enable_ifをまったく使用しないことを検討できます。単にfを特化することは可能です:
template <int N>
struct S {
template<class T> int f(T t);
};
template<int N>
template<class T>
int S<N>::f(T t) { return 2; }
template<>
template<class T>
int S<1>::f(T t) { return 1; }
int main() {
S<1> s1;
return s1.f(99);
}