Cos’è un contesto non condotto?

Recentemente sono stato esposto a questa domanda e le risposte possono essere riassunte in “È un contesto non condotto”.

Nello specifico, il primo dice che è una cosa del genere e quindi reindirizza allo standard per i “dettagli”, mentre il secondo cita lo standard, che è a dir poco criptico.

Qualcuno può spiegare a semplici mortali, come me, che contesto non è deducibile , quando si verifica e perché si verifica?

È molto semplice: la deduzione si riferisce al processo di determinazione del tipo di parametro di un modello da un determinato argomento. Si applica a modelli di funzioni, auto e pochi altri casi (es. Specializzazione parziale). Ad esempio, considera:

 template  void f(std::vector); 

Ora se dici f(x) , dove hai dichiarato std::vector x; , allora T è dedotta come int , e ottieni la specializzazione f .

Affinché la deduzione funzioni, il tipo di parametro del modello che deve essere dedotto deve apparire in un contesto deducibile. In questo esempio, il parametro function di f è un contesto così deducibile. Cioè, un argomento nella funzione call expression ci consente di determinare quale sia il parametro T del template in modo che l’espressione call sia valida.

Tuttavia, esistono anche contesti non ridotti, in cui non è ansible alcuna detrazione. L’esempio canonico è “un parametro template che appare a sinistra di un ::

 template  struct Foo; template  void g(typename Foo::type); 

In questo modello di funzione, la T nella lista dei parametri della funzione si trova in un contesto non dedotto. Quindi non puoi dire g(x) e dedurre T La ragione di ciò è che non esiste una “corrispondenza all’indietro” tra tipi arbitrari e membri Foo::type . Ad esempio, potresti avere delle specializzazioni:

  template <> struct Foo { using type = double; }; template <> struct Foo { using type = double; }; template <> struct Foo { using type = bool; }; template <> struct Foo { int type = 10; }; template <> struct Foo { }; 

Se chiami g(double{}) ci sono due possibili risposte per T , e se chiami g(int{}) non c’è risposta. In generale, non esiste alcuna relazione tra i parametri del modello di class e i membri della class, quindi non è ansible eseguire alcuna deduzione ragionevole.


Occasionalmente è utile inibire esplicitamente la deduzione degli argomenti. Questo è ad esempio il caso di std::forward . Un altro esempio è quando si hanno conversioni da Foo a Foo , dire, o altre conversioni (si pensi a std::string e char const * ). Supponiamo ora di avere una funzione gratuita:

 template  bool binary_function(Foo lhs, Foo rhs); 

Se chiami binary_function(t, u) , la deduzione potrebbe essere ambigua e quindi fallire. Ma è ragionevole dedurre un solo argomento e non dedurre l’altro, permettendo così conversioni implicite. Ora è necessario un contesto esplicitamente non dedotto, ad esempio in questo modo:

 template  bool binary_function(Foo lhs, typename std::common_type>::type rhs) { return binary_function(lhs, rhs); } 

(Potresti aver riscontrato problemi di deduzione simili a qualcosa come std::min(1U, 2L) .)