Почему я могу частично специализироваться, но не могу полностью специализировать шаблоны элементов в C ++?

Правила шаблонов IMO, C ++ кажутся слишком строгими, и реализация компилятора определена. Но здесь у меня есть определенное поведение, мне было трудно обернуть голову вокруг.

В следующей задаче я сознательно стараюсь избегать явной специализации родительского класса.

Проблема в том, что я могу частично специализировать участника, но не могу специализировать его полностью. Что действительно противоречит интуиции, потому что вы можете легко добавить фиктивный шаблон в полностью специализированный шаблон и сделать его частично специализированным. Что тут происходит??

Важное редактирование: это важно, потому что, как мы знаем, вы не можете специализировать функции-члены, не специализируя также и класс (который можно рассматривать как комбинацию этой проблемы, нужно быть частично специализированным, и тот факт, что c ++ не разрешить частично специализированные функции. Я не знаю, связаны ли они, но, по крайней мере, они согласованы), поэтому, если вам нужен функционал в вашем классе, вы можете специализироваться на использовании функторов. И вдобавок ко всему, вам нужно добавить фиктивный параметр шаблона, чтобы это работало !!

Это работает:

template <class T>
class A
{
template<typename Y, typename Z>
struct C{
void operator()(int x);
};

template<typename Z>
struct C<int, Z>{
void operator()(int x);
};
};

template <class T>
template <typename Z>
void A<T>::C<int, Z>::operator()(int x){

}

Но это не так:

template <class T>
class A
{
template<typename Y>
struct C{
void operator()(int x);
};

template<>
struct C<int>{
void operator()(int x);
};
};

template <class T>
template <>
void A<T>::C<int>::operator()(int x){

}

Изменить: Шон Ф. в комментариях отметил, что компилятору трудно выбрать специализацию. Но проблема в том, что частичная специализация не устраняет эту проблему. Так что это не может быть ответом.

5

Решение

Как правило, специализация шаблонной функции — плохая идея. Используйте перегрузки или диспетчеризацию тегов. Например:

template<class T>struct tag_t{};

template<class T>
auto foo(T& t){ return foo( tag_t<T>{}, t ); }

Теперь мы можем использовать перегрузки для отправки:

void foo( tag_t<int>, int& i ){ i+=3; }
template<class T>
void foo( tag_t<T>, T& t ){ t*=2; }

здесь не происходит никакой специализации. Мы используем правила разрешения перегрузки, чтобы выбрать реализацию. И это хорошо работает с членами.

Мы используем специализацию только на классах высшего уровня. Даже там я часто испытываю искушение выбирать реализации путем отправки тегов и использования decltype, поскольку разрешение перегрузки часто дает лучшее сопоставление с образцом.

Если вам действительно нужен класс-член, замените его на класс верхнего уровня и несколько объявлений друзей.

template<class T, class Y>
struct A_C;
template <class T>
class A
{
template<class T0, class Y0>
friend class A_C<T0, Y0>;
template<class Y>
using C=A_C<T,Y>;
};
template<class T, class Y>
struct A_C {
// implementation of A::C
};

Теперь у вас есть довольно неограниченная специализация A_C Вот. Ни одной из твоих проблем.

3

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

Других решений пока нет …

По вопросам рекламы [email protected]