When is deleting a template instantiation preferable to deleting a non-template overload?

怎甘沉沦 提交于 2019-12-03 11:04:08

问题


Suppose I have a template that works with raw pointers:

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

I don't want this to be called with void* pointers. It seems I have two choices. I can delete a non-template overload:

void processPointer(void*) = delete;

Or I can delete a template instantiation:

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

Declaring the non-template overload is easier (no futzing with angle brackets). Are there reasons why I'd prefer to delete the template instantiation instead?


回答1:


Here's one reason to favor the template version: processPointer<void>(void*) can still be invoked directly, avoiding the other overload.




回答2:


I don't see any reason to go templating here

In fact, by deleting the non-template overload you may wiggle your way out of some edge-case ambiguous calls that I can't think of right now, since non-templates take precedence over template instantiations. And thus make this work as desired in a majority of cases.




回答3:


This might give insight:

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

Conclusion: The answer of @Casey holds.




回答4:


Suppose you want to pass the argument pointer of type void* (or simply nullptr) to your processPointer function and you also want to call its specialization for type Type. Then you should write

processPointer(static_cast<Type>(pointer));

for

void processPointer(void*) = delete;

But for

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

you could write the code which is much shorter:

processPointer<Type>(pointer);

So both variants can be used in the different cases.

However the analogue of the variant with non-template overload can be the only way in some cases. Suppose there is a function template with two parameters:

template<typename T, typename U>
void processPointer(T* ptr1, U* ptr2);

You don't want it to be called with void* pointers as the first argument. The partial specialization of function templates is not allowed in C++ so this code is incorrect:

template<typename U>
void processPointer<void, U>(void*, U*) = delete;

And you must use another one:

template<typename U>
void processPointer(void*, U*) = delete;


来源:https://stackoverflow.com/questions/21028144/when-is-deleting-a-template-instantiation-preferable-to-deleting-a-non-template

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!