c++ templates c++11 sfinae static-assert

c++ - ¿Cuándo usar `static_assert` en lugar de SFINAE?



templates c++11 (4)

Creo que static_assert es la opción correcta si desea imponer que T es un tipo de punto flotante. Este método establece su intención más claramente que la solución SFINAE.

He estado usando (y visto usado) static_assert para marcar valores no deseados de valores de parámetros de plantilla. Sin embargo, para todos los casos que encontré, parece mejor y más elegante desactivar esos valores no deseados a través de SFINAE. Por ejemplo

template<typename T, class = std::enable_if<std::is_floating_point<T>::value>::type> struct Foo { ... };

en lugar de

template<typename T> struct Foo { static_assert(std::is_floating_point<T>::value, "Foo<T>: T must be floating point :-("); ... };

Entonces, mi pregunta: ¿cuándo usar static_assert lugar de SFINAE y por qué?

EDITAR

Creo que lo que he aprendido hasta ahora es el siguiente

1 SFINAE es una herramienta versátil y poderosa pero potencialmente muy complicada que puede usarse para muchas tareas, incluida la resolución de sobrecarga de funciones (que algunos parecen considerar como su único propósito).

2 SFINAE se puede usar de una manera relativamente simple donde está siempre static_assert , excepto que aparece en la declaración (de una clase o función) en lugar de su definición (o es posible insertar una static_assert en, por ejemplo, una declaración de clase hacia adelante ?). Eso hace más textual y por lo tanto un código más claro. Sin embargo, debido a que SFINAE es complicado, tiende a ser más difícil de corregir que una simple static_assert .

3 Por otra parte, static_assert tiene la ventaja de un mensaje de error más claro del compilador, que algunos parecen considerar como el propósito principal de cualquiera.


Por un lado, el uso de SFINAE puede llevar a que se recoja otra sobrecarga que originalmente era una combinación peor y no se consideraría.

Y en la situación de que hay otras sobrecargas, pero ninguna de ellas es viable, obtienes algunas cosas buenas como esta:

#include <type_traits> void f(int){} void f(bool){} void f(char){} void f(float){} void f(long){} void f(double){} void f(short){} void f(unsigned){} void f(void*){} void f(void (*)()){} template<class C, class T = int> using EnableIf = typename std::enable_if<C::value, T>::type; template<class T> struct sfinae_false : std::false_type{}; template<class T> void f(T&&, EnableIf<sfinae_false<T>> = 0){} int main(){ struct X{}; f(X()); }

Salida:

source.cpp: In function ''int main()'': source.cpp:23:30: error: no matching function for call to ''f(main()::X)'' source.cpp:23:30: note: candidates are: source.cpp:3:6: note: void f(int) source.cpp:3:6: note: no known conversion for argument 1 from ''main()::X'' to ''int'' source.cpp:4:6: note: void f(bool) source.cpp:4:6: note: no known conversion for argument 1 from ''main()::X'' to ''bool'' source.cpp:5:6: note: void f(char) source.cpp:5:6: note: no known conversion for argument 1 from ''main()::X'' to ''char'' source.cpp:6:6: note: void f(float) source.cpp:6:6: note: no known conversion for argument 1 from ''main()::X'' to ''float'' source.cpp:7:6: note: void f(long int) source.cpp:7:6: note: no known conversion for argument 1 from ''main()::X'' to ''long int'' source.cpp:8:6: note: void f(double) source.cpp:8:6: note: no known conversion for argument 1 from ''main()::X'' to ''double'' source.cpp:9:6: note: void f(short int) source.cpp:9:6: note: no known conversion for argument 1 from ''main()::X'' to ''short int'' source.cpp:10:6: note: void f(unsigned int) source.cpp:10:6: note: no known conversion for argument 1 from ''main()::X'' to ''unsigned int'' source.cpp:11:6: note: void f(void*) source.cpp:11:6: note: no known conversion for argument 1 from ''main()::X'' to ''void*'' source.cpp:12:6: note: void f(void (*)()) source.cpp:12:6: note: no known conversion for argument 1 from ''main()::X'' to ''void (*)()'' source.cpp:21:6: note: template<class T> void f(T&&, EnableIf<sfinae_false<T> >) source.cpp:21:6: note: template argument deduction/substitution failed:


Utiliza SFINAE, si quieres que se use otra sobrecarga, y static_assert si ninguno de ellos se ajusta a ese parámetro.


static_assert hace que la compilación falle. SFINAE le permite eliminar una posible sobrecarga.