(Parcialmente) especialización de un parámetro de plantilla no tipo de tipo dependiente


Tal vez estoy cansado, pero estoy atascado con esta especialización parcial simple, que no funciona porque non-type template argument specializes a template parameter with dependent type 'T':

template <typename T, T N> struct X;
template <typename T>      struct X <T, 0>;

Sustituyendo 0 por T(0), T{0} o (T)0 no ayuda. Entonces, ¿es posible esta especialización?

Author: Barry, 2014-03-18

4 answers

Véase el párrafo [temp.clase.spec] 14.5.5 / 8 de la norma:

El tipo de un parámetro de plantilla correspondiente a un argumento no tipo no será dependiente de un parámetro de la especialidad. [ Ejemplo:

template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error

template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error

-ejemplo final ]

La respuesta a su edición: la solución más fácil es reemplazar un parámetro de plantilla que no sea de tipo por uno de tipo:

#include <type_traits>

template <typename T, typename U>
struct X_;

template <typename T, T N>
struct X_<T, std::integral_constant<T, N>> {};

template <typename T>
struct X_<T, std::integral_constant<T, 0>> {};

template <typename T, T N>
struct X : X_<T, std::integral_constant<T, N>> {};
 23
Author: Constructor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-18 19:43:29

Solución usando la solución de Yakk:

#include <iostream>
#include <type_traits>

template <typename T, T N, typename = void > 
struct X {
  static const bool isZero = false;
};

template <typename T, T N>
struct X < T, N, typename std::enable_if<N == 0>::type > {
  static const bool isZero = true;
};

int main(int argc, char* argv[]) {
    std::cout << X <int, 0>::isZero << std::endl;
    std::cout << X <int, 1>::isZero << std::endl;
    return 0;
}

Demostración En Vivo

 7
Author: Sam Cristall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-18 17:47:26

Puede agregar un parámetro typename=void al final de la lista de argumentos template, luego ir hog wild con std::enable_if_t< condición > en especializaciones.

 3
Author: Yakk - Adam Nevraumont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-18 17:32:10

Necesita pasar un valor integral en una plantilla, tanto la primera como la segunda plantilla no funcionarán si el tipo T no es un tipo integral.

Puede pasar Traits como un parámetro de plantilla escrito para especificar el valor N:

#include <iostream>

// error: ‘double’ is not a valid type for a template non-type parameter
template <typename T, T N> struct X0;

// error: ‘double’ is not a valid type for a template non-type parameter
template <typename T, T N, int = 0> struct X1;



template <typename T, T N>
struct IntegralTraits {
    static constexpr T Value() { return N; }
};

template <typename T, typename Traits = void>
struct X2 {
    static constexpr T Value() { return Traits::Value(); }
};

template <typename T>
struct X2<T, void> {
    static constexpr T Value() { return T(); }
};


int main() {
    // error: ‘double’ is not a valid type for a template non-type parameter
    // X0<double, 0>();

    // error: ‘double’ is not a valid type for a template non-type parameter
    // X1<double, 0>();

    X2<int> a;
    X2<double, IntegralTraits<int, 1>> b;

    std::cout.precision(2);
    std::cout << std::fixed  <<  a.Value() << ", "<< b.Value() << '\n';
    return 0;
}

Si se limita a los tipos integrales, elija uno grande:

template <typename T, std::size_t N = 0> struct X {};
 0
Author: Dieter Lücking,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-18 18:10:09