c++ - Seleccione el constructor de clase usando enable_if
templates sfinae (2)
Considera seguir el código:
#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;
}
Quiero definir selectivamente el constructor A :: A (int) solo para algunos tipos usando enable_if. Para todos los demás tipos existe el constructor predeterminado A :: A (...) que debería ser el caso predeterminado para el compilador cuando falla la sustitución. Sin embargo, esto tiene sentido para mí compilador (gcc versión 4.9.0 20130714) todavía se queja
sfinae.cpp: en instanciación de ''struct A'': sfinae.cpp: 19: 11:
requerido desde aquí sfinae.cpp: 9: 5: error: ningún tipo llamado ''tipo'' en
''struct std :: enable_if''
A (int n): val (n) {};
¿Algo como esto es posible para el constructor? ¿Es esto posible con otro constructor (s) (copy-constructor y move-constructor)?
Creo que esto no puede funcionar con un único parámetro de plantilla predeterminado, porque su valor debe resolverse cuando se crea una instancia de la plantilla de clase.
Necesitamos diferir la sustitución al punto de instanciación de la plantilla del constructor. Una forma es predeterminar el parámetro de plantilla a T y agregar un parámetro ficticio adicional al constructor:
template<typename U = T>
A(int n, typename std::enable_if<U::value>::type* = 0) : val(n) { }
Por lo general, esto se hace usando un argumento anónimo predeterminado:
A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {};
No puede usar los parámetros de plantilla de la clase a los métodos SFINAE out. ASÍ, una forma es agregar un tipo ficticio reemplazando 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;
}
Esto funciona porque usted usa un parámetro de plantilla de miembro para SFINAE fuera del constructor pero la prueba siempre es verdadera para que no contamine sus cheques