2012-03-09 13 views

risposta

15

In C++ 03, la specifica vieta esplicitamente l'argomento di default venga utilizzato per dedurre un argomento di template (C++ 03 §14.8.2/17):

A template type-parameter cannot be deduced from the type of a function default argument.

In C++ 11 , è possibile fornire un argomento modello predefinito per il modello di funzione:

template <typename T = float> 
void bar(int a, T b = 0.0f) { } 

L'argomento di modello predefinito è obbligatorio, tuttavia. Se l'argomento del modello predefinito non viene fornito, l'argomento della funzione predefinita non è ancora utilizzabile per la deduzione degli argomenti del modello. Specificamente, vale (C++ 11 14.8.2.5/5):

The non-deduced contexts are:

...

  • A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done.
+10

Mentre dire "Perché lo standard dice così" è una risposta valida, sarebbe bello conoscere il ragionamento che c'è dietro. –

+1

Tra le altre ragioni, dichiarazioni diverse di una funzione possono dichiarare diversi argomenti predefiniti (sono abbastanza sicuro che lo stesso si applica ai modelli di funzione). –

+1

@James: No, dichiarazioni diverse non possono dichiarare argomenti predefiniti diversi. Non è nemmeno permesso che più dichiarazioni diano lo stesso valore predefinito allo stesso argomento. 8.3.6 dice "Un argomento di default non deve essere ridefinito da una dichiarazione successiva (nemmeno con lo stesso valore)." Ovviamente, ciò vale solo per le funzioni non di modello. Per le funzioni del modello, sembra che gli argomenti predefiniti possano essere forniti solo nella dichiarazione iniziale. –

4

Una buona ragione potrebbe essere che

void foo(bar, xyzzy = 0); 

è simile ad una coppia di sovraccarichi.

void foo(bar b) { foo(b, 0); } 
foo(bar, xyzzy); 

Inoltre, a volte è vantaggioso refactoring in tale:

void foo(bar b) { /* something other than foo(b, 0); */ } 
foo(bar, xyzzy); 

Anche quando scritto come uno, è ancora come due funzioni in un unico, nessuno dei quali è "preferito" in alcun senso . Stai chiamando la funzione a un argomento; quello a due argomenti è effettivamente una funzione diversa. La notazione degli argomenti predefinita li fonde in uno solo.

Se il sovraccarico dovesse avere il comportamento che si sta richiedendo, quindi per coerenza dovrebbe funzionare nel caso in cui il modello è diviso in due definizioni. Ciò non avrebbe senso perché quindi la deduzione sarebbe tirare i tipi da una funzione non correlata che non viene chiamata! E se non fosse implementato, significherebbe che sovraccaricare diverse lunghezze di lista dei parametri diventa un "cittadino di seconda classe" rispetto a "default-argumenting".

È utile se la differenza tra sovraccarico e impostazione predefinita è completamente nascosta al client.

7

Ci sarebbero alcune difficoltà tecniche nel conseguirlo in generale. Ricordare che gli argomenti predefiniti nei modelli non vengono istanziati finché non sono necessari. Si consideri poi:

template<typename T, typename U> void f(U p = T::g()); // (A) 
template<typename T> T f(long, int = T()); // (B) 
int r = f<int>(1); 

Questo si risolve oggi eseguendo (tra l'altro) le seguenti operazioni:

  1. tentativo di dedurre parametri di modello per i candidati (A) e (B); fallisce per (A), che viene quindi eliminato.
  2. esegue la risoluzione di sovraccarico; (B) è selezionato
  3. forma la chiamata, istanziare l'argomento di default

Al fine di dedurre da un argomento di default, tale argomento di default dovrebbe essere in sé istanziato prima di completare il processo di deduzione. Ciò potrebbe fallire, causando errori al di fuori del contesto di SFINAE. Ad esempio, un candidato che potrebbe essere del tutto inappropriato per una chiamata potrebbe innescare un errore.

+0

Suoni ragionevoli per me. –

Problemi correlati