Differenza tra specializzazione esplicita e funzioni regolari quando si sovraccarica una funzione modello

StackOverflow https://stackoverflow.com/questions/5986935

Domanda

Sono in giro oggi.Ecco n00b domanda numero 7:

Qual è la differenza tra la specializzazione esplicita e solo le funzioni regolari quando si tenta di sovraccaricare una funzione di modello?

Qual è la situazione appropriata per utilizzare la specializzazione esplicita?Non lo capisco bene:

#include <iostream>

template <typename s> void test(s var1);
template <> void test<int>(int var1);

int main(){
    test(1);
    test(1.1);
    test("hello!!");
    return 0;
}

template <typename s> void test(s var1){
    std::cout << var1 << std::endl;
}

template <> void test<int>(int var1){
    std::cout << "int " << var1 << std::endl;
}

Come opporsi a:

#include <iostream>

template <typename s> void test(s var1);
void test(int var1);

int main(){
    test(1);
    test(1.1);
    test("hello!!");
    return 0;
}

template <typename s> void test(s var1){
    std::cout << var1 << std::endl;
}

void test(int var1){
    std::cout << "int " << var1 << std::endl;
}
È stato utile?

Soluzione

Non c'è davvero una differenza tra una funzione modello esplicitamente specializzata e una funzione regolare non modello diversa dal fatto che quando il compilatore cerca un tipo di firma corrispondente per la chiamata della funzione, prenderà prima un modello non modello Funzione che corrisponde alla firma richiesta prima di provare a istanziare le funzioni del modello disponibili che potrebbero soddisfare la corrispondenza della firma richiesta.

Se si sta per dichiarare e definire una funzione all'interno di un file di intestazione non una funzione modello, però, dovrai dichiarare la funzione come inline. Questo perché una funzione modello non è una funzione effettiva collegata con un modulo di codice finché non viene effettivamente istanziata. Il linker lancia quindi l'istanziazione dopo aver compilato il modulo di codice. Se il linker non ha fatto questo, allora ogni volta che un file .cpp ha incluso il file di intestazione, il linker si lamenterà sulle definizioni duplicate per una funzione. L'utilizzo della parola chiave inline su una funzione non modello ha un effetto simile al livello del compilatore, in quanto qualsiasi volta la funzione viene utilizzata in un file .cpp, il compilatore sostituisce quella chiamata con il corpo del codice della funzione inline Nel file di intestazione ed evita il sovraccarico di una chiamata di funzione con un'installazione e la pulizia del record attivo dello stack associato. Pertanto il linker non si lamenterà delle definizioni duplicate per una funzione.

Altri suggerimenti

Non sono un esperto, ma la mia esperienza è utilizzare modelli (e specializzazione) quando voglio definire diversi tipi di ritorno.Non è possibile sovraccaricare il tipo di ritorno di una funzione.

Una grande differenza è:Le specializzazioni esplicite non partecipano affatto al sovraccarico.

template<typename T> void f(T const&);
template<> void f<char const*>(char const * const&);

Chiamare con f("hello") non prenderà in considerazione alcuna specializzazione esplicita.Prenderà solo tutti i modelli e dedurrà i loro argomenti del modello.Quanto sopra T sarà dedotto a char[6], e così la specializzazione non sarà selezionata.

Se invece sovraccarichi il modello di funzione, hai caratteristiche completamente diverse.

template<typename T> void f(T const&);
void f(char const * const&);

Chiamando questo, selezionerà la seconda funzione, perché sia il (char const(&)[6]) parametro della specializzazione generata e il (char const * const&) il parametro corrisponde ugualmente bene all'argomento, ma la seconda funzione è una funzione non modello, quindi alla fine è preferita.

Quando il compilatore arriva su una chiamata di funzione, cerca per la prima volta una funzione non modello di definizione, quindi un modello esplicitamente specializzato e infine, una definizione del modello la cui firma corrisponde alla chiamata della funzione. Quindi, ad esempio, se si dispone di un modello esplicitamente definito e un modello, il compiere è per il modello definito esplicitamente.Pertanto, è necessario utilizzare un modello specializzato esplicito quando si desidera gestire un particolare tipo di dati in un modo diverso dal modo in cui il modello lo avrebbe gestito.

Un altro uso per la specializzazione esplicita è quando si desidera "sovraccaricare" una funzione che non prende alcun argomento.È possibile utilizzare la specializzazione esplicita per fornire diverse definizioni alla funzione per gestire diversi tipi di dati.

IMHO, la specializzazione esplicita per function template deve essere utilizzata quando, si chiamano quella funzione utilizzando l'argomento del modello esplicito.ad esempio.

test<int>(myClass); // no argument for 'int' -> declare test() as template specialization
.

In altri casi, è necessario utilizzare sempre la normale specializzazione.ad esempio.

test(10, myClass); // argument 10 is 'int' -> test() should be normal specialized
.

Tecnicamente non vi è alcuna differenza tra la specializzazione del modello normale ed esplicita di una funzione.Le normali versioni specializzate sono completamente indipendenti dalle funzioni template.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top