Newsgroup: it.comp.lang.c++
Titolo: Templates con codice type-dependent?

Salve a tutti.
Ho dei codici (di ottimizzazione) nei quali alcuni tipi di dato in principio
possono essere di diversi formati (int, short, float, double ...). Fino ad
ora - anche perche' per diverso tempo i templates non sono stati ben
implementati su molti compilatori - me la sono cavata semplicemente definendo
dei tipi astratti ("Number") e lavorando solo con quelli.
Ora, la soluzione C++ elegante sarebbe invece quella di usare le template
class. Il che andrebbe benissimo, non fosse che alcune operazioni devono
essere diverse per diversi tipi di dato (fate conto i test "== 0", che con
gli interi sono semplicemente cosi' mentre con i float devono avere un qualche
epislon). Io ho sempre risolto queste cose a botte di #if(), a la C, il che
funziona benissimo ma naturalmente ha lo svantaggio che qualunque scelta io
faccia e' fissata per tutto l'eseguibile. E non e' elegante.
Allora, io avevo pensato di sfruttare il fatto che le templates possono
avere anche argomenti costanti, e di usare un argomento come flag. Visto
che in principio un template e' "circa" una macro, poteva anche darsi che
un codice come il seguente funzionasse:
template<class T, const int TisFLOAT>
class Test
{
 public:
 Test( const T v )
 { 
  val = v;
  #if( TisFLOAT )
   eps = 1e-6;
  #endif
  }
 int EQZ( void )
 {
  #if( TisFLOAT )
   return( ( val >= -eps ) && ( val <= eps ) );
  #else
   return( val == 0 );
  #endif
  }
 #if( TisFLOAT )
  void Seteps( const T ne ) { eps = ne; }
 #endif
 private:
 T val;
 #if( TisFLOAT )
  T eps;
 #endif
 };  // end( class( Test ) )
int main( void )
{
 Test<int, 0> t1( 10 );
 Test<float, 1> t2( 5 );
 t2.Seteps( .1 );
 t1.EQZ();
 t2.EQZ();
 return( 0 );
 }  // end( main() )
Invece *non* funziona: evidentemente (a posteriori) il problema e' che le
#if() vengono valutate una volta sola all'inizio, e non ogni volta che il
template e' istanziato.
Qualcuno ha suggerimenti per come girare intorno alla cosa, o idee alternative?
Avete mai visto cose del genere fatte da altre parti? Qualunque suggerimento o
commento e' benvenuto.
                                       Saluti & Buon Natale
                                             Antonio
Antonio Frangioni                      Research Associate  |  I have gained ...
Dip. di Informatica - Corso Italia 40 - 56125 Pisa, Italy  |  the colour of the
Ph +039-50-887216                
www.di.unipi.it/~frangio
  |  corn.   [Exupery]

 commento e' benvenuto.
Io proverei a demandare all'operatore di confronto (ma anche altri) del
tipo oggetto del template di operare sul tipo stesso.
Il problema si risolve per tutti i tipi definiti da utente ma purtroppo
non risolve il problema operator== su float o double in quanto non e'
possibile ridefinire operatori su tipi predefiniti.
Utilizzando funzioni ordinarie al posto degli operatori invece e'
possibile aggirare il problema, pero' e' secondo me meno elegante.
Non so se sono stato chiaro, o se mi e' sfuggito qualcosa pero' credo
possa essere un inizio.
Ciao.
-- 
     (ZZZ)       Filippo Salotti, Bagni di Lucca, Lucca, Italy.
    //   \\  _                 E-mail : 
fil...@humnet.unipi.it
   /Y\    ZD<_o===============================================o
 .oZZZZZo.     | Studente Ingegneria Informatica Automatica  |
<OXXXXXXXO>    | Dip. Sistemi Elettrici Universita' di Pisa. |

epislon). Io ho sempre risolto queste cose a botte di #if(), a la C, il che
Appunto per questo tipo di situazioni, il linguaggio C++
prevede che si possano specializzare i template per certi
tipi-parametro specifici.
L'idioma piu` elegante e generale e` quello dei "traits", un
template che raggruppa le varie operazioni e caratteristiche
di tuo interesse.  Ad esempio:
// caso-default
template <typename T>
class comparison_traits {
public:
    static inline bool equal(T t1, T t2) {
        return t1==t2;
    }
    // eccetera
};
// casi speciali
template<> class comparison_traits<double> {
public:
    static inline bool equal(double t1, double t2) {
        return fabs(t1-t2) < epsilon;
    }
    // eccetera
};
// dovrai ripeterlo per float, long double, ecc, o se no
// fare qualche trucchetto di eredita` per risparmiare
// di digitare qualche riga...:-)
Dopo di che, in tutti i tuoi template, puoi usare
    typedef comparison_traits<T> compare;
    // ...
    if(compare.equal(t1, t2))
        // ecc ecc
o, meglio ancora, prendere compare come un
parametro con _default_ comparison_traits<T>,
per potere ulteriormente "personalizzare a
compile-time" l'esatto comportamento del tuo
template.
Alex