(Частично) специализация нетипичного параметра шаблона зависимого типа

Может быть, я устал, но я застрял с этой простой частичной специализацией, которая не работает, потому что 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>;

Замена 0 от T(0), T{0} или же (T)0 не помогает Так возможна ли эта специализация?

24

Решение

См. Пункт [temp.class.spec] 14.5.5 / 8 стандарта:

Тип параметра шаблона, соответствующий специализированному
не тип аргумента не должен зависеть от параметра
специализация. [ Пример:

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

— конец примера ]

Ответ на ваши изменения: самый простой обходной путь — заменить нетипичный параметр шаблона типовым:

#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

Другие решения

Решение с использованием решения Якка:

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

Live Demo

7

Вы можете добавить typename=void параметр до конца списка template аргументы, а затем сходить с ума std::enable_if_t< состояние > по специализациям.

3

Вам нужно передать интегральное значение в шаблоне. Оба, ваш первый и второй шаблон, не будут работать, если тип T не является целочисленным.

Вы можете передать черты как типизированный параметр шаблона, чтобы указать значение 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;
}

Если вы ограничиваете себя целочисленными типами, выберите большой:

template <typename T, std::size_t N = 0> struct X {};
0
По вопросам рекламы [email protected]