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

后端 未结 4 814
再見小時候
再見小時候 2021-02-05 06:04

Suppose I have a template that works with raw pointers:

template
void processPointer(T* ptr);

I don\'t want this to be called

相关标签:
4条回答
  • 2021-02-05 06:34

    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.

    0 讨论(0)
  • 2021-02-05 06:38

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

    0 讨论(0)
  • 2021-02-05 06:43

    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;
    
    0 讨论(0)
  • 2021-02-05 06:48

    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.

    0 讨论(0)
提交回复
热议问题