2014-01-09 2 views
18

Предположим, у меня есть шаблон, который работает с сырыми указателями:Когда удаляется экземпляр шаблона, предпочтительнее удаления перегрузки без шаблонов?

template<typename T> 
void processPointer(T* ptr); 

Я не хочу, чтобы это можно назвать с void* указателями. Кажется, у меня есть два выбора. Я могу удалить перегрузки без шаблона:

void processPointer(void*) = delete; 

Или я могу удалить шаблон экземпляра:

template<> 
void processPointer<void>(void*) = delete; 

Декларирование перегрузки без шаблонов не проще (не возиться с угловыми скобками). Есть ли причины, по которым я предпочел бы удалить экземпляр шаблона вместо этого?

+1

+1, потому что я не знаю ответ сам. Я бы удалил экземпляр шаблона, потому что я склонен думать о целом наборе перегрузок в качестве шаблонов. Я думаю, было бы легче понять, что происходит позже, когда читаешь код (т. Е. Следуйте принципу наименьшего удивления). Я не знаю, есть ли технические причины выбирать так или иначе. – utnapistim

ответ

4

Я не вижу никаких причин, чтобы пойти шаблонирования здесь

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

4

Это может дать представление:

#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 держит.

+2

Что вы думаете, что может дать? (Я думаю, что знаю, но поскольку вы на самом деле не сказали, я не уверен. Пожалуйста, напишите предложение или два, чтобы повторить, что должен иллюстрировать код.) –

+1

'template <> void X :: processPointer (void *) = delete; 'или без параметра deduced' template <> void X :: processPointer (void *) = delete; '[может быть специализированным вне области видимости класса] (http: //coliru.stacked- crooked.com/a/d5e781c971aa54b0 "Демо-код в Coliru"). – Casey

16

Here's one reason в пользу версии шаблона: processPointer<void>(void*) все еще можно вызвать напрямую, избегая другой перегрузки.

+2

+1, поскольку явно указывается аргумент шаблона в общем коде. –

0

Предположим, что вы хотите передать аргумент 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; 
Смежные вопросы