5

Si consideri il seguente codice:lista variadica vs parametro template singolo: cosa dice lo standard?

#include <iostream> 
#include <type_traits> 

// Variadic version 
template<class... Variadic> 
void f(const Variadic&... variadic) 
{ 
    std::cout<<"variadic"<<std::endl; 
} 

// Single version 
template<class Single, class = typename std::enable_if<std::is_fundamental<Single>::value>::type> 
void f(const Single& single) 
{ 
    std::cout<<"single"<<std::endl; 
} 

// Main 
int main() 
{ 
    f();    // variadic 
    f(42);   // single : why? 
    f(std::string()); // variadic 
    f(42, 42);  // variadic 
    return 0; 
} 

Non capisco il motivo per cui la linea marcata "single" compila bene (sotto g ++ 4.6.3) e non produce un problema di risoluzione di sovraccarico. Lo standard C++ 11 dice che una funzione template con un numero fisso di parametri è preferibile rispetto a una funzione variadica che potrebbe avere la stessa firma?

risposta

2

A causa dell'uso del secondo parametro enable_if, modello nella versione "singola", il compilatore considera tale versione come un modello più specializzato da utilizzare con i tipi per cui è abilitato.
È considerato più specializzato perché ci sono tipi in cui il modello variadic può essere istanziato, ma il "singolo" non può.

La regola generale è che un modello più specializzato supera un modello meno specializzato nella risoluzione di sovraccarico.

+0

Nota: il parametro 'enable_if' non ha nulla a che fare con il sovraccarico" Single "che è più specializzato, è ortogonale e serve a * rimuovere * la funzione dall'insieme di possibili sovraccarichi. –

+1

Ma quando non si rimuove la funzione, si ottiene 'f (const int &)' che è più specializzato di 'f (const int &)'.Il fatto che il secondo parametro template sia 'enable_if' non è rilevante. ma il fatto che abbia un secondo parametro è rilevante ed è la ragione per cui viene scelto il sovraccarico. Sostituire il tipo 'enable_if' con' void' rende tale overload fattibile per 'f (std :: string())' e quindi viene anche selezionato per quella chiamata come più specializzato. –

+0

@MatthieuM. Sono d'accordo che questo è l'intento di usare 'enable_if'. Come spiega Jonathan, un suo effetto collaterale sta rendendo il modello più specializzato per quei casi in cui non viene rimosso. –

5

It is reallyquite simple (due esempi, gcc e clang)

template<class...T> void foo(T&&...) {std::cout << "...T\n";} 
template<class T> void foo(T&&) {std::cout << "T\n";} 
int main() { 
    foo(3); 
} 

sovraccarichi non prendere ... sembrano essere preferito quando la scelta è un parametro di modello esplicito.

Il class=std::enable_if_t non modifica questo.

Quindi entrambe le funzioni f sono candidate, quindi il compilatore preferisce quella senza variardics.

14.8.2.4 dedurre argomenti del template durante ordinamento parziale [temp.deduct.partial]

/8:

Se A stato trasformato da un pacco parametro di funzione e P non è un pacchetto di parametro, la deduzione del tipo fallisce. In caso contrario, utilizzando i tipi risultanti P e A, la detrazione viene quindi eseguita come descritto in 14.8.2.5. Se P è un pacchetto di parametri funzione, il tipo A di ogni restante tipo di parametro del modello di argomento viene confrontato con il tipo P del dichiaratore-id del pacchetto di parametri della funzione. Ogni confronto deduce gli argomenti del modello per le posizioni successive nei pacchetti di parametri del modello espansi dal pacchetto del parametro della funzione. Se la deduzione ha esito positivo per un determinato tipo, il tipo dal modello dell'argomento viene considerato almeno altrettanto specializzato del tipo dal modello di parametro. [ Esempio:

template<class... Args> void f(Args... args); // #1 
template<class T1, class... Args> void f(T1 a1, Args... args); // #2 
template<class T1, class T2> void f(T1 a1, T2 a2); // #3 
f(); // calls #1 
f(1, 2, 3); // calls #2 
f(1, 2); // calls #3; non-variadic template #3 is more 
// specialized than the variadic templates #1 and # 

In particolare, l'esempio f(1,2).

Tutta la clausola enable_if_t rimuove la versione a un argomento dalla considerazione quando si passa uno std::string come T.