Предположим, у меня есть шаблон, который работает с необработанными указателями:
template<typename T>
void processPointer(T* ptr);
Я не хочу, чтобы это вызывали с void*
указатели. Кажется, у меня есть два варианта. Я могу удалить не шаблонную перегрузку:
void processPointer(void*) = delete;
Или я могу удалить шаблонный экземпляр:
template<>
void processPointer<void>(void*) = delete;
Объявлять перегрузку, не связанную с шаблоном, проще (без сглаживания угловыми скобками). Есть ли причины, по которым я бы предпочел вместо этого удалить создание экземпляра шаблона?
Вот одна из причин в пользу версии шаблона: processPointer<void>(void*)
все еще может быть вызван напрямую, избегая другой перегрузки.
Я не вижу причин для шаблонов здесь
На самом деле, удаляя не шаблонную перегрузку, вы можете вылезти из некоторых неоднозначных вызовов крайнего случая, о которых я не могу думать сейчас, так как не-шаблоны имеют приоритет над экземплярами шаблонов. И, таким образом, сделать эту работу, как желательно в большинстве случаев.
Это может дать понимание:
#include <iostream>
struct X
{
template<typename T>
void processPointer(T* ptr) {
std::cout << "Template\n";
}
// error: explicit specialization in non-namespace scope ‘struct X’
// template<>
// void processPointer(void*) = delete;
// Overload but no specialization
// This will prevent lookup the specialization outside the class, when no
// template argument is explicitly given. However, with an explicit
// template argument the specialization is called.
void processPointer(void*) = delete;
};
// Specialization outside the class body
template<>
void X::processPointer(void* ptr) {
std::cout << "Specialization\n";
}
int main ()
{
X x;
//error: use of deleted function ‘void X::processPointer(void*)’
//x.processPointer((void*)0);
// Explicit template argument:
x.processPointer<void>((void*)0);
}
Вывод: ответ @Casey верен.
Предположим, вы хотите передать аргумент pointer
типа void*
(или просто nullptr
) на ваш processPointer
функция, и вы также хотите вызвать его специализацию для типа Type
, Тогда вам следует написать
processPointer(static_cast<Type>(pointer));
за
void processPointer(void*) = delete;
Но для
template<>
void processPointer<void>(void*) = delete;
Вы можете написать код, который намного короче:
processPointer<Type>(pointer);
Таким образом, оба варианта могут быть использованы в разных случаях.
Однако аналог варианта с не шаблонной перегрузкой может быть единственным способом в некоторых случаях.
Предположим, есть шаблон функции с двумя параметрами:
template<typename T, typename U>
void processPointer(T* ptr1, U* ptr2);
Вы не хотите, чтобы это вызывали с void*
указатели в качестве первого аргумента. Частичная специализация шаблонов функций не разрешена в C ++, поэтому этот код неверен:
template<typename U>
void processPointer<void, U>(void*, U*) = delete;
И вы должны использовать другой:
template<typename U>
void processPointer(void*, U*) = delete;