Newsgroup: it.comp.lang.c++
Titolo: Problema con i template

Ciao!
All'interno di un metodo di un template, è possibile ricavare il tipo su cui
è stato costruito? Mi spiego meglio. Ho una classe definita così:
template <class T> class myTemplate
All'interno del template, posso definire un metodo "Foo" che, a seconda di
cosa è T (int, char, short, ecc.) esegua delle azioni diverse? Come?
Come sempre, grazie a tutti!
Riccardo

 cosa è T (int, char, short, ecc.) esegua delle azioni diverse? Come?
Io di solito faccio cosi' (nel mio esempio i tipi possibili di T sono 
Plan e Deal, due classi), non sono sicuro che sia il metodo migliore 
tuttavia:
template <class T>
class IsType
{
     public:
         enum {Plan = false };
         enum {Deal = false };
};
template <>
class IsType<Deal>
{
     public:
         enum {Deal = true };
         enum {Plan = false };
};
template <>
class IsType<Plan>
{
     public:
         enum {Deal = false };
         enum {Plan = true };
};
Nella funzione della tua classe:
template <class T>
myTemplate::foo()
{
	if (IsType<T>::Plan)
		// Gestisci roba specifica di plan
	else if (IsType<T>::Deal)
		// gestisci roba specifica di deal
}
In teoria l'ottimizzatore e' in grado di rimuovere le if dei tipi non 
usati in quanto in fase di compilazione dopo la sostituzione dei 
template diventerebbero "if (false)" e "if (true) ".
Bye,
  Gabry

 template diventerebbero "if (false)" e "if (true) ".
C'è lo stesso un problema: il contenuto dell'if viene compilato anche se
l'if è sempre falso. Quindi potresti fare cose illegali. Si può provare
anche con l'overloading dei metodi. (il compilatore non compila le funzioni
che non vengono richiamate)
--- bye

 che non vengono richiamate)
Cose illegali di che tipo? Ho appena fatto un test e la seconda stringa 
non viene proprio inclusa nell'eseguibile, anche senza ottimizzatore:
[gabry@nevada tmp]$ g++ -O2 prova.cpp
[gabry@nevada tmp]$ grep PPPP ./a.out
Binary file ./a.out matches
[gabry@nevada tmp]$ grep DDDD ./a.out
[gabry@nevada tmp]$ g++ prova.cpp
[gabry@nevada tmp]$ grep PPPP ./a.out
Binary file ./a.out matches
[gabry@nevada tmp]$ grep DDDD ./a.out
Ecco il sorgente completo:
#include <iostream>
class Plan {  int a; };
class Deal {  short a; };
template <class T>
class IsType
{
     public:
         enum {Plan = false };
         enum {Deal = false };
};
template <> class IsType<Deal>
{
     public:
         enum {Deal = true };
         enum {Plan = false };
};
template <> class IsType<Plan>
{
     public:
         enum {Deal = false };
         enum {Plan = true };
};
template <class T> void foo()
{
     if (IsType<T>::Plan)
         std::cout << "PPPPPPP!" << std::endl;
     else if (IsType<T>::Deal)
         std::cout << "DDDDDDD!" << std::endl;
}
int main()
{
    foo<Plan>();
}
Bye,
  Gabry

 non viene proprio inclusa nell'eseguibile, anche senza ottimizzatore:
Vero, ma viene lo stesso compilato. Quindi se l'espressione è illegale, ti
può sparare un errore. Prova a mettere nel pezzo di programma che viene
saltato un comando inesistente e vedi se si lamenta.
--- bye

 saltato un comando inesistente e vedi se si lamenta.
Ok, questo lo sapevo, ma non capisco la pericolosita' della cosa :)
Nel senso, mi sembra molto piu' pericoloso l'overload dei metodi, 
perche' se perdi il controllo di quali metodi sono overloadati e quali 
no puoi chiamare la funzione sbagliata a runtime che e' decisamente 
peggio di un errore compile time :)
Bye,
  Gabry

 cosa è T (int, char, short, ecc.) esegua delle azioni diverse? Come?
Ci sono vari trucchetti. Ad esempio:
 template< class T > struct  Foo_tag {};
 template<> struct  Foo_tag<char>    {};
 template<> struct  Foo_tag<int>     {};
 template<> struct  Foo_tag<short>   {};
 template< class T >
 class myTemplate
 {
    public:
       void Foo()
        {
            Foo_impl( Foo_tag<T>() );
        }
    private:
       void Foo_impl( Foo_tag<char> )
       {
       }
       void Foo_impl( Foo_tag<int> )
       {
       }
         // etc..
 };

 Riccardo
Io ho un'altra cosa da proporre per risolvere il suo problema che 
non mi sembra sia stata citata:
puoi usare le RTTI (run-time type identification) del C++
Ecco un esempio:
#include <typeinfo>
template<class T>
class mia_classe {
        public:
 
        void foo();
}
template<class T> void mia_classe<T>::foo() {
        if (typeid(T) == typeid(int)) {
                //fai una cosa...
        } else if (typeid(T) == typeid(char*)) {
                //ne fai un'altra...
        } 
}
Be', cmq per i piccoli problemi ti conviene usare l'overloading delle
funzioni, ma se hai davvero il bisogno di capire in tempo reale il tipo di
un template puoi usare questa soluzione. Attenzione pero', con i
compilatori vecchi potresti avere qualche problema di incompatibilita'.
Nell'esempio che ti ho mostrato non dovresti avere problemi nemmeno con il
VC++ 6, ma sei limitato a quello.
Per esempio il g++ mi permette qualche metodo in piu':
puoi fare typeid(mia_classe).name() //Restituisce una const char * con il
nome del tipo. Varia da compilatore a compilatore. Con il g++ funziona
bene.
typeid(mia_classe).__is_pointer_p() restituisce 0 o 1 a seconda se quel
template e' un puntatore o no. Sotto il VC++ 6.0 NON FUNZIONA.
Ciao!
-- 
Vladislav Valtchev

Gabriele Greco wrote:

Il mio consiglio e' di fare dei semplice overload:
template <class T>
class myTemplate
{
private:
   void foo (int) { ... };
   void foo (float) { ... };
   ....
public:
   void foo() {
	foo(T());
   }
};
G.

 peggio di un errore compile time :)
Non capisco come si fa a perdere il controllo dei metodi overloaded.
Ad ogni modo la tua soluzione non e' fattibile se ad esempio la classe
Plan ha un metodo che non ha la classe Deal:
template <class T>
myTemplate::foo()
{
     T t;
     if (IsType<T>::Plan) {
	t.questo_metodo_esiste_solo_in_deal();
     }
     else if (IsType<T>::Deal) {
	t.questo_metodo_esiste_solo_in_deal();
     }
}
facendo cosi' ottieni codice non compilabile.
G.

  };
Non e' molto piu' semplice specializzare Foo_impl?
Ciao,
Nicola

consiglio vivamente a tutti il libro "Modern C++ Design - Generic
Programming and Design Patterns Applied", di Andrei Alexandrescu.
Spiega bene una infinità di incredibili magie che si possono fare con
i template.


E' vero. Mi dimentico sempre che si possono specializzare le singole funzioni
membro, senza dover specializzare l'intera classe.
Max

...

Ottimo libro, ma nel caso specifico e' ancor piu' indicato "C++
Templates - The Complete Guide" di N. Josuttis e D. Vandevoorde.
Ciao,
Nicola