2015-10-02 7 views
12

Dopo anni di codifica in C++, oggi mi è stata posta una semplice domanda, ma in effetti non ho trovato la sua risposta e quindi eccomi qui.Nessuna trasmissione automatica da `int` a` float` con Template Function

Oltre chiedendo perché questo errore sta accadendo, voglio sapere come posso risolvere sotto l'errore modificando solo la funzione di modello (senza cambiare la funzione main())

template <class T> 
T Add(T first, T second) 
{ 
    return first + second; 
} 

int main() 
{ 
    auto sample_1 = Add(1, 2); // Works 
    auto sample_2 = Add(1.f, 2.f); // Works 
    auto sample_3 = Add(1.f, 2); // Error: no instance matches the argument types: (double, int) 
    return 0; 
} 
+3

introdurre classe 'T2' o fare' secondo' non desumibile con 'decltype (primo) secondo? –

+0

Scenario interessante però. Penso che un interruttore del compilatore di default avrebbe dovuto essere implementato per gestire tali casi ... – sjsam

risposta

16

Oltre a chiedersi il motivo per cui questo errore sta accadendo,

Quando si chiama Add(1.f, 2), il primo tipo di argomento è float e il secondo tipo di argomento è int.

Il compilatore deve convertire il primo argomento in unoo il secondo argomento in uno float. Dal momento che entrambi richiedono una conversione, sono candidati altrettanto validi. Uno non può essere preferito all'altro.

voglio sapere come posso risolvere sotto l'errore modificando solo la funzione di modello

È possibile modificare il modello di funzione di:

template <class T1, class T2> 
auto Add(T1 first, T2 second) 
{ 
    return first + second; 
} 

o (grazie @PiotrSkotnicki) :

template <class T> 
T Add(T first, decltype(first) second) 
{ 
    return first + second; 
} 

In questo caso, il tipo di second non viene dedotto dall'argomento passato alla funzione. Il tipo di first viene dedotto dal primo argomento e il tipo di second deve essere uguale al tipo di first.

Add(1.2f, 2); // The first argument is deduced to be float 
       // The second argument is forced to be float. 

Add(2, 1.2f); // The first argument is deduced to be int 
       // The second argument is forced to be int. 
+2

Dovresti spiegare come funziona quel secondo esempio magico, perché quando il commento di Piotr è inevitabilmente messo a tacere. –

9

Basta fare :

template <class T1, class T2> 
auto Add(T1 first, T2 second) 
{ 
    return first + second; 
} 

come unica T, si evince una volta come int, una volta come double ...

1

Vorrei sapere come posso risolvere sotto l'errore modificando solo la funzione di modello

Come quella:

template <class T1, class T2> 
T1 Add(T1 first, T2 second) 
{ 
    T1 p; 
    p = first + second; 
    return p; 
} 

int main() 
{ 
    auto sample_1 = Add(1, 2); 
    auto sample_2 = Add(1.f, 2.f); 
    auto sample_3 = Add(1.f, 2); 
    return 0; 
} 
4

Quando si dispone di

template <class T> 
T Add(T first, T second) 

il tipo di first e second devono essere gli stessi. Se si vuole prendere due tipi diversi, allora si può aggiungere un secondo parametro di template

template <class T1, class T2> 
auto Add(T1 first, T2 second) 

o per C++ 11

template <class T1, class T2> 
auto Add(T1 first, T2 second) -> decltype(first + second) 
+1

'T' non è dichiarato quindi non può essere usato come tipo di ritorno, e scrivere il tipo restituito correttamente quindi' T1' e 'T2' sono diversi è possibile , ma abbastanza complicato (a meno che non si usi 'auto' come in altre risposte) che probabilmente deve essere indirizzato perché la tua risposta sia davvero utile all'OP. – hvd

+0

@hvd Ho aggiornato la mia risposta – NathanOliver

3

Il compilatore sta tentando di dedurre il tipo di modello che può utilizzare per creare una funzione che corrisponde alla firma. Poiché i parametri sono di tipo diverso, non è in grado di farlo.

è possibile specificare il tipo in modo esplicito:

auto sample_3 = Add<float>(1.f, 2); 

Ma tu dici che non vuoi farlo.

È possibile modificare la funzione di prendere due tipi di modello:

template <class T1, class T2> 
T1 Add(T1 first, T2 second) 
{ 
    T1 p; 
    p = first + second; 
    return p; 
} 

Ma ora si dovrà fare una supposizione su quale tipo di tornare.

non ho mai provato a utilizzare auto come tipo di ritorno, ma a quanto pare funziona: http://ideone.com/1qO95w

template <class T1, class T2> 
auto Add(T1 first, T2 second) 
{ 
    auto p = first + second; 
    return p; 
} 
+0

grazie per la tua risposta. nota che 'T' non è definito nel tuo codice. – Emadpres

+0

@Emadpres ringrazia, quello era un semplice errore di copia/incolla. Ho anche arricchito la risposta con 'auto'. –

+0

È una nuova funzionalità di C++ 14 che non posso usare. grazie comunque e ti do il tuo sforzo +1:] – Emadpres

2

Perché scrivere la propria funzione quando lo standard già fornito loro?

in C++ 11, è possibile utilizzare:

#include <functional> 
int main() 
{ 
    auto sample_1 = std::plus<float>() (1, 2); // Works 
    auto sample_2 = std::plus<float>() (1.f, 2.f); // Works 
    auto sample_3 = std::plus<float>() (1.f, 2); // Works 
    return 0; 
} 

in C++ 14:

#include <functional> 
int main() 
{ 
    auto sample_1 = std::plus<>() (1, 2); // Works 
    auto sample_2 = std::plus<>() (1.f, 2.f); // Works 
    auto sample_3 = std::plus<>() (1.f, 2); // Works 
    return 0; 
}