c++ studio ¿Cuándo es preferible eliminar una creación de instancias de plantilla que eliminar una sobrecarga que no sea de plantilla?




manual android studio avanzado (4)

Supongamos que tengo una plantilla que funciona con punteros en bruto:

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

No quiero que se llame con punteros void* . Parece que tengo dos opciones. Puedo eliminar una sobrecarga que no sea de plantilla:

void processPointer(void*) = delete;

O puedo eliminar una instancia de plantilla:

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

La declaración de la sobrecarga sin plantilla es más fácil (no utilizar bloques con ángulo). ¿Hay razones por las que prefiero eliminar la creación de instancias de plantilla en su lugar?


Supongamos que desea pasar el pointer de argumento de tipo void* (o simplemente nullptr ) a su función processPointer y también desea llamar a su especialización para el tipo Type . Entonces deberías escribir

processPointer(static_cast<Type>(pointer));

para

void processPointer(void*) = delete;

Pero para

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

Usted podría escribir el código que es mucho más corto:

processPointer<Type>(pointer);

Entonces ambas variantes pueden ser utilizadas en los diferentes casos.

Sin embargo, el análogo de la variante con sobrecarga sin plantilla puede ser la única forma en algunos casos. Supongamos que hay una plantilla de función con dos parámetros:

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

No desea que se llame con punteros void* como primer argumento. La especialización parcial de las plantillas de función no está permitida en C ++, por lo que este código es incorrecto:

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

Y debes usar otro:

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

No veo ninguna razón para ir a la plantilla aquí.

De hecho, al eliminar la sobrecarga sin plantillas puede salir de algunas llamadas ambiguas de caso extremo en las que no puedo pensar ahora, ya que las no plantillas tienen prioridad sobre las instancias de las plantillas. Y así hacer que funcione como se desea en la mayoría de los casos.


Esto podría dar una idea:

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

Conclusión: La respuesta de @Casey sostiene.


Aquí hay una razón para favorecer la versión de la plantilla: processPointer<void>(void*) aún se puede invocar directamente, evitando la otra sobrecarga.





overloading