Newsgroup: it.comp.lang.c++
Titolo: Template e tipo restituito

ciao a tutti, è la prima volta che posto qui, ecco subito il mio problema...
ho il seguente template:
template <typename tipo1>
tipo1 max(tipo1 a, tipo1 b)
{
	if (a>b) return a;
	else return b;
}
a cui, attraverso l'overloading dell'operatore ">" faccio fare il 
confronto tra due numeri complessi definiti in una classe a parte in 
base al loro modulo... vorrei usare lo stesso template per confrontare, 
sempre tramite il modulo, un complesso e un double... il template diventa:
template <typename tipo1, typename tipo2>
*quale_tipo???* max(tipo1 a, tipo2 b)
{
	if (a>b) return a;
	else return b;
}
il mio problema è che se il maggiore è il complesso devo restituire un 
complesso, se il maggiore è il double devo restituire quest'ultimo... 
come fare a far variare il tipo restituito?
ciao,
2m23

 come fare a far variare il tipo restituito?
La definizione del tipo di ritorno avviene in fase di compilazione e non puņ
pertanto essere subordinata al risultato del confronto, che sarą noto solo
in fase di esecuzione. 
Max


Prima di tutto al tuo posto eviterei di chiamare la tua funzione max,
dal momento che la libreria standard contiene gia' una funzione
template max() praticamente identica alla tua.
Assumendo che nel tuo tipo complesso le parti reali e immaginaria
siano rappresentati come double quello che ti conviene fare e'
definire due funzioni separate che restituiscono un complesso:
complesso max(double d, complesso c) {
  return d >= c.reale() ? complesso(d,0) : c;
}
complesso max(complesso c, double d) {
  return max(d, c);
}
E quindi aggiungere al tuo complesso un operatore di conversione a
double. Attenzione che se il tuo complesso ha un costruttore che
prende un singolo valore come parametro deve essere dichiarato
explicit.
Un'alternativa piu' macchinosa in C++, ma piu' simile a come
funzionano i linguaggi di scripting e' usare un tipo che puo' assumere
valori di tipo diverso dinamicamente, come boost::any (vedi
boost.org
).
Ciao,
Nicola

 
boost.org
).
come funziona a livello di occupazione in memoria? non vorrei che 
occupasse il massimo possibile per poi "ridimensionarsi"...
ciao,
2m23

 occupasse il massimo possibile per poi "ridimensionarsi"...
No, e' allocato dinamicamente e si rialloca ogni volta che assegni un
valore.
Ciao,
Nicola

 valore.
molto interessante, ti ringrazio, ma penso che al professore non 
piacerà... ;)
ciao,
2m23

 explicit.
ho ragionato su questo punto...
se faccio un template in questo modo:
template <typename T, typename U>
T max(T a, U b)
{
	if (a>b) return a;
	else
	{
		complesso c(b,0);
		return c;
	}
}
vengo meno al principio del template (perchè "forzo" il complesso)... 
invece se il template è del tipo:
template <typename T, typename U>
T max(T a, U b)
{
	if (a>b) return a;
	else
	{
		T c(b,0);
		return c;
	}
}
credo che a run-time funzioni, ma non so se è corretto farlo dal punto 
di vista "filosofico" in quanto in un certo senso costringo il template 
a comportarsi per restituire un determinato tipo... che ne pensate?
ciao,
2m23

 }
uff, poi non funziona se voglio confrontare due complessi... cerco 
qualche altra soluzione.
ciao,
2m23

 2m23
template <typename T, typename U>
T max(T a, U b)
{
     if (a>b) return a;
     else
     {
         T c = b;
         return c;
     }
}
Implementi il costruttore di copia del complex da double ed in questo 
modo ti funziona anche comparando due double
Ciao

 Ciao
ciao,
2m23

 a comportarsi per restituire un determinato tipo... che ne pensate?
E' persino peggio del precedente, perche' potrebbe portarti a
situazioni inaspettate, ad esempio se chiamo
max(std::complex(2.0,3.0), 4.0);
Comunque, visto che sei interessato, leggiti questo: http://
www.ddj.com/dept/cpp/184403774
Ciao,
Nicola

 modo ti funziona anche comparando due double
Poi qualcuno ti passa gli argomenti invertiti e sei nelle peste...
Ciao,
Nicola

 
Beh, torna comunque il primo tipo (probabile che abbia implementato 
operatori di conversione, confronto, ecc. tra complex e double) e se un 
double puo' essere accettato al posto di complex, non vedo nessun problema.
Al limite, se proprio vuole, puo' specializzare per il caso inverso.
Ciao

 Ciao
Ripensandoci, è vero, si perde la parte immaginaria.
L'overloading sul tipo di ritorno non si può fare, deve mettere per 
contratto di non usare quella forma.
D'altra parte per guidare occorre la patente, occorre conoscere i 
segnali e non si deve andare contromano :-)
Poi se uno lo fa ...
Ciao

 Poi se uno lo fa ...
E' vero, ma questa non e' una buona scusa per infliggere al prossimo
codice disegnato male. Perche' tu e 2M23 non provate a migliorare
l'esempio che ho postato ieri, invece di incaponirvi su questo vicolo
cieco?
Ciao,
Nicola

 
ok, avevo detto una mezza cavolata (non ho scusanti, ma forse l'ora 
presta...)
ho buttato giů una cosa minimale, giusto per verificare.
Basta specializzare, o meglio, mettere prima del template il metodo 
specifico che darebbe problemi.
Ciao
//---------------------------------------------
class myCplx
{
public:
   myCplx(double r, double im = 0) : R(r), Im(im) {}
   myCplx(const myCplx& other) : R(other.R), Im(other.Im) {}
   double operator()() { return R; }
   const myCplx& operator=(const myCplx& other) { R = other.R; Im = 
other.Im; }
   const myCplx& operator =(double d) { R = d; Im = 0; }
   double R;
   double Im;
};
//---------------------------------------------
bool operator >(const myCplx& c1, const myCplx& c2)
{
   // giusto per esempio
   return c1.R > c2.R;
}
//---------------------------------------------
myCplx myMax(double d, myCplx c)
{
   if(d > c)
     return d;
   return c;
}
//---------------------------------------------
template <typename T, typename C>
T myMax(T v1, C v2)
{
   if(v1 > v2)
     return v1;
   T t = v2;
   return t;
}
//---------------------------------------------
   myCplx a(10.0, 8.0);
   double b = 5;
   myCplx c(3.0, 3.0);
   myCplx d = myMax(b, a);
   myCplx e = myMax(b, c);
   myCplx f = myMax(c, b);
   myCplx g = myMax(f, a);
   myCplx h = myMax(b, 3.0);
   myCplx i = myMax(b, 13.0);

    return c;}
myCplx myMax(myCplx c, double d)
{
   return myMax(d,c);
}
E lascia stare il template, tanto qualsiasi argomento di un tipo
numerico nativo viene convertito automaticamente a double. Anzi, forse
cambierei il double in long double, accettando una possibile piccola
penalizzazione prestazionale in cambio della certezza di coprire
correttamente tutti i casi possibili.
Ciao,
Nicola

 correttamente tutti i casi possibili.
scusate, ho abbandonato la discussione per qualche giorno... allora, 
vediamo se ho capito:
logicMind usa il template per i due casi (complesso-complesso) e 
(complesso-double) e quindi specifica una funzione apposta per 
"specializzare" il caso (double-complesso).
tu invece consigli di lasciar stare il template, vero? non ne ho capito 
la motivazione... e poi non ho capito il perchè di quell' "explicit"...
grazie mille per la pazienza!
ciao,
2m23

 e poi non ho capito il perchè di quell' "explicit"...
Perche' se ho sia una conversione da MyCplx a double che da double a
MyCplx rischio di incappare in ambiguita' quando chiamo operazioni con
parametri misti.
Ciao,
Nicola