Domanda

L'ultima domanda ho chiesto era qualcosa che mi sono imbattuto su quando si cerca di capire un'altra cosa ... che anche io non riesco a capire (non il mio giorno).

Questa è una domanda piuttosto una dichiarazione a lungo, ma almeno spero che questa domanda potrebbe rivelarsi utile a molte persone e non solo a me.

Il codice che ho è il seguente:

template <typename T> class V;
template <typename T> class S;

template <typename T>
class V
{
public:
 T x;

 explicit V(const T & _x)
 :x(_x){}

 V(const S<T> & s)
 :x(s.x){}
};

template <typename T>
class S
{
public:
 T &x;

 explicit S(V<T> & v)
 :x(v.x)
 {}
};

template <typename T>
V<T> operator+(const V<T> & a, const V<T> & b)
{
 return V<T>(a.x + b.x);
}

int main()
{
 V<float> a(1);
 V<float> b(2);
 S<float> c( b );

 b = a + V<float>(c); // 1 -- compiles
 b = a + c;           // 2 -- fails
 b = c;               // 3 -- compiles

 return 0;
}

Espressioni 1 e 3 funzionano perfettamente, mentre l'espressione 2 non viene compilato.

Se ho capito bene, ciò che accade è:

Espressione 1

  1. c è implicitamente convertito in const utilizzando una sequenza di conversione standard (composto da un solo conversione qualificazione ).
  2. V<float>(const S<T> & s) viene chiamato e ha generato un oggetto l'const V<float> temporale (chiamiamolo t ). E 'già const qualificato perché è un valore temporale.
  3. a viene convertito in const in modo simile a c .
  4. operator+(const V<float> & a, const V<float> & b) viene chiamato, con conseguente temporale di tipo const V<float> che possiamo definire q .
  5. il V<float>::operator=(const & V<float>) di default è chiamata.

I Am OK fino a qui? Se ho fatto anche il più sottile errore per favore, fatemelo sapere, perché io sto cercando di acquisire una comprensione del casting implicito il più profondamente possibile ...

Expression 3

  1. c viene convertito in V<float>. Per questo, abbiamo una sequenza di conversione definita dall'utente:
    1.1. Conversione primo standard:. S<float> per const S<float> tramite la conversione di qualificazione
    1.2. definito dall'utente conversione: const S<float> per V<float> via V<float>(const S<T> & s) costruttore
    . 1,3 secondi conversione standard:. V<float> per const V<float> tramite la conversione di qualificazione
  2. il V<float>::operator=(const & V<float>) di default è chiamata.

Expression 2?

Quello che non capisco è perché c'è un problema con la seconda espressione. Perchè è la seguente sequenza non è possibile?

  1. c viene convertito in V<float>. Per questo, abbiamo una sequenza di conversione definita dall'utente:
    1.1. iniziale conversione standard:. S<float> per const S<float> tramite la conversione di qualificazione
    1.2. definito dall'utente conversione: const S<float> per V<float> via V<float>(const S<T> & s) costruttore
    . 1.3. conversione standard finale: V<float> per const V<float> tramite la conversione di qualificazione.
  2. passaggi da 2 a 6 sono le stesse come nel caso di espressione 1.

Dopo aver letto il C ++ standard I però: 'hey! forse il problema deve a con 13.3.3.1.2.3!' che afferma:

  

Se la conversione definita dall'utente è specificato da una funzione di conversione modello, la seconda sequenza di conversione standard deve avere esattamente rango partita.

Ma questo non può essere il caso, in quanto la conversione di qualificazione ha corrispondenza esatta rango ...

ho davvero idea ...

Bene, se hai la risposta o no, grazie per la lettura fino a qui:)

È stato utile?

Soluzione

Come Edric ha sottolineato, le conversioni non sono considerati durante la deduzione modello di argomentazione. Qui, ci sono due contesti in cui il modello di parametro T può essere dedotta dal tipo degli argomenti:

template<class T>
v<T> operator+(V<T> const&, V<T> const&);
               ~~~~~~~~~~~  ~~~~~~~~~~~~

Ma si tenta di richiamare questo modello di funzione con una V<float> sul lato sinistro e una S sul lato destro della strada. Template risultati argomento deduzione in T = galleggiante per il lato sinistro e si otterrà un errore per il lato destro, perché non c'è modo che T V<T> uguale S<T>. Questa qualifica come un fallimento detrazione modello argomento e il modello viene semplicemente ignorato.

Se si desidera consentire conversioni proprio operatore + non dovrebbe essere un modello. V'è il seguente trucco: è possibile definire come un amico in linea all'interno del modello di classe per V:

template<class T>
class V
{
public:
   V();
   V(S<T> const&); // <-- note: no explicit keyword here

   friend V<T> operator+(V<T> const& lhs, V<T> const& rhs) {
      ...
   }
};

In questo modo, l'operatore non è un modello più. Quindi, non v'è alcuna necessità di detrazione modello argomento e la vostra invocazione dovrebbe funzionare. L'operatore è trovato attraverso ADL (argomento di ricerca dipendente) perché il lato sinistro è un V<float>. Il lato destro è correttamente convertito in un V<float> pure.

E 'anche possibile disabilitare la deduzione modello argomento per uno specifico argomento. Ad esempio:

template<class T>
struct id {typedef T type;};

template<class T>
T clip(
   typename id<T>::type min,
   T value,
   typename id<T>::type max )
{
   if (value<min) value=min;
   if (value>max) value=max;
   return value;
}

int main() {
   double x = 3.14;
   double y = clip(1,x,3); // works, T=double
}

Anche se il tipo del primo e l'ultimo argomento è un int, essi non sono considerati nel modello detrazione argomento perché id<T>::type non è un cosiddetto context` * deducibili. Quindi, T si deduce solo in base al secondo argomento, che si traduce in T = doppia con contraddizioni.

Altri suggerimenti

Quando si considerano le partite di modello, le conversioni implicite non vengono utilizzati. Pertanto, nel seguente esempio semplice:

template < typename T >
void foo( T t1, T t2 ) { /* do stuff */ }

int main( int argc, char ** argv ) {
    foo( 1, 1.0 );
    return 0;
}

Non verrà compilato anche se uno degli argomenti potrebbe essere convertito in modo implicito l'altro tipo (int <-> doppia).

Solo una supposizione, ma forse il compilatore non può distinguere tra la conversione da V> S o da S-> V durante il tentativo di capire come aggiungere un + c nell'espressione 2. Si sta assumendo il compilatore sarà abbastanza intelligente per scegliere quello che permette la compilazione di procedere a causa di tutto il resto delle funzioni disponibili, ma il compilatore non è probabilmente "lettura avanti" (si fa per dire), ed è sempre confusa con l'ambiguità del up-conversione prima cercando di trovare l'operatore '+'.

Naturalmente, se si aggiunge l'errore di compilazione, potrebbe contribuire a chiarire il problema troppo ...

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