Pourquoi compiler l'erreur avec enable if
Pourquoi cela ne compile pas avec gcc48 et 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);
}
Erreur 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 erreur:
/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;
^
MODIFIER-SOLUTION
J'ai accepté la réponse de Charles Salvia, mais pour des raisons pratiques, je n'ai pas pu utiliser la solution de contournement proposée (se spécialiser sur N). J'ai trouvé une autre solution de contournement qui fonctionne pour moi. Faites en sorte que enable_if
dépende de T
:
typename std::enable_if<(sizeof(T),N==1), int>::type
5 réponses
Parce que vous utilisez enable_if
sans utiliser le paramètre template T
dans vos modèles de fonction. Si vous souhaitez vous spécialiser lorsque la structure S
a une certaine valeur de paramètre de modèle N
, vous devrez utiliser la spécialisation de modèle de classe.
template <int N, class Enable = void>
struct S { };
template <int N>
struct S<N, typename std::enable_if<N == 1>::type>
{
....
};
Eh bien, je ne suis pas sûr de ce que vous vouliez faire, mais peut-être que ce code aidera:
#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);
}
Cela imprime 1 et 2.
Utilisez un paramètre de modèle booléen par défaut, comme ceci:
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;};
};
Pour que std::enable_if
fonctionne comme ça, vous comptez sur SFINAE. Malheureusement, au moment où vous déclarez
S<1> s1;
Il instanciera toutes les déclarations des membres de S<1>
. SFINAE n'entrera en jeu à ce stade que si S<1>
était une construction mal formée. Il n'est pas. Malheureusement, il contient une fonction qui n'est pas valide, donc l'instanciation de S<>
n'est pas valide.
Pour des choses comme celle-ci, je pourrais m'en remettre à une structure de modèle distincte:
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); }
};
Pour ce cas, vous pourriez penser à ne pas utiliser enable_if du tout. Il est possible de simplement se spécialiser 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);
}