logo c++ templates metaprogramming sfinae enable-if

c++ - logo - ¿Por qué compilar error con enable_if



hbase (5)

¿Por qué esto no compila con gcc48 y 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); }

Error 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;}; ^

Error 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; ^

EDITAR - SOLUCIÓN

He aceptado la respuesta de Charles Salvia, pero por razones prácticas no pude usar la solución propuesta (se especializa en N). Encontré otra solución que funciona para mí. Hacer que enable_if dependa de T :

typename std::enable_if<(sizeof(T),N==1), int>::type


Bueno, no estoy seguro de lo que querías hacer, pero quizás este código ayude:

#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); }

Esto imprime 1 y 2.


Para este caso, podría pensar en no usar enable_if en absoluto. Es posible simplemente especializarse 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); }


Para que std::enable_if funcione de esta manera, confía en SFINAE. Desafortunadamente, en el punto donde usted declara

S<1> s1;

instanciará todas las declaraciones de miembros de S<1> . SFINAE solo entrará en juego en este punto si S<1> fuera una construcción mal formada. No lo es. Desafortunadamente, contiene una función que no es válida, por lo que la creación de instancias de S<> no es válida.

Para cosas como esta, podría referirme a una estructura de plantilla separada:

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); } };


Porque usa enable_if sin usar el parámetro de plantilla T en sus plantillas de funciones. Si desea especializarse cuando la estructura S tiene un determinado valor de parámetro de plantilla N , deberá utilizar la especialización de plantilla de clase.

template <int N, class Enable = void> struct S { }; template <int N> struct S<N, typename std::enable_if<N == 1>::type> { .... };


Utilice un parámetro de plantilla booleano predeterminado, como este:

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;}; };