Правила шаблонов 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){
}
Изменить: Шон Ф. в комментариях отметил, что компилятору трудно выбрать специализацию. Но проблема в том, что частичная специализация не устраняет эту проблему. Так что это не может быть ответом.
Как правило, специализация шаблонной функции — плохая идея. Используйте перегрузки или диспетчеризацию тегов. Например:
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
Вот. Ни одной из твоих проблем.
Других решений пока нет …