Newsgroup: it.comp.lang.c++
Titolo: Ancora Template! :-))

Allora,
   mi sa che ho un qualche problema di progetto di base ... (le funzioni
qui di seguito sono state buttate giu' al volo ... tollerate gli eventuali
errori e se non sono stato chiaro, chiedete pure! :-)) ).
   1. Ho una classe base:
class PinoBase {
public:
               PinoBase();
   virtual     ~PinoBase();
};
   2. Ho una classe definita attraverso un template:
template <class DataType>
class Pino: public PinoBase {
public:
               Pino();
   virtual     ~Pino();
private:
   DataType * mData;
};
   3. Ho un insieme di operatori statici:
template <class DataTypeX, class DataTypeY>
bool  AreCompatible(
           Pino<DataTypeX> * inX,
           Pino<DataTypeY> * inY);
   4. Ho una classe che include come membro un puntatore alla classe base:
class Pippo {
public:
   PinoBase * GetBase()
                  { return mBase; }
private:
   PinoBase * mBase;
};
   5. In una funzione definita da tutta un'altra parte, ho bisogno di
applicare l'operatore opportuno ai dati della classe Pippo. Essendo pero'
questi definiti in termini della classe base, ovviamente il compilatore mi
dice che la chiamata a:
   Pippo x, y;
   bool res = AreCompatible(x->GetBase(), y->GetBase());
   ... e' cannata! Ovviamente non posso dargli torto :-))
   Allora, mi chiedo, c'e' un modo per risolvere questo problema? L'unica
cosa che mi e' venuta in mente (orrida ...), e' che ogni classe basata su
template abbia una qualche funzione che ritorna il tipo di dato, e prima
della chiamata alla funzione in (5) definisco gli argomenti all'interno di
uno switch. Roba da far rizzare i capelli! :-))
      Cris

Cristiano Verondini wrote in message ... [snip]
un classico problema di "double dispatch", che gli si
presenta con dei template ma in realta` non ha nulla
a che vedere coi template -- infatti, si riduce a questo:
-- ho una classe base B,
-- tante classi C,D,E,F,...,derivate da B (di numero
    potenzialmente illimitato)
-- tante funzioni "statiche" (=non membri di classi):
        void pippo(C*, D*);
    ecc, overloaded per tutte le varie classi
    derivate da B
-- in una funzione x ho due puntatori a B,
    B*p1 e B*p2, vorrei chiamare la "giusta"
    pippo secondo quale sia l'effettivo "tipo
    dinamico" (effettiva classe derivata) cui
    appartengono gli oggetti puntati
e questo e` appunto il problema del doppio
dispatch -- scelta di una funzione dipendente
dai tipi dinamici di DUE oggetti.
Se la dipendenza fosse dal tipo di uno solo dei
due oggetti, cioe` se dovessi chiamare la giusta
pluto(C*) o pluto(D*) eccetera sulla base del tipo
di un oggetto solo, la soluzione sarebbe, assai
chiaramente, quella di inserire in B una funzione
virtuale pura:
class B {
// ...
public:    virtual void call_pluto() = 0;
};
con override in ogni classe derivata, tipo:
class C {
//
public:    virtual void call_pluto() { pluto(this); }
};
Purtroppo il meccanismo, comodo, veloce, e
sicuro, della chiamata virtuale, non si generalizza
al dispatch multiplo (cioe` sui tipi dinamici di due
o piu` argomenti).  Ci sono parecchi approcci
parziali (pattern Visitor, Virtual Visitor, ecc), che
possono aiutare in tanti casi particolari importanti,
ma non una soluzione generale perfettamente
soddisfacente.
La soluzione generale e` usare una mappa da
(tuple di) typeinfo a puntatori a funzioni (si puo`
usare il meccanismo virtuale per una dimensione).
Presenta problemi di costruzione della mappa e
prestazioni non eccellenti (benche` migliori delle
alternative "in codice", come switch o serie di
if/else if/... basate sul typeinfo o equivalente).
In generale (non sempre...) e` possibile, come si
suol dire, "re-fattorizzare" la progettazione del
sistema, sapendo quanto problematico sia il
dispatch multiplo, per evitare di scontrarcisi
frontalmente.
Alex

 frontalmente.
   In effetti mi rendo conto che arrivato a questo punto il gioco si
faccia parecchio piu' complesso di come l'avevo pensato (mancanza di
un'adeguata fase di progettazione :-(( ).
   BTW, il problema e' formulabile in questo modo (piu' o meno). Ho delle
matrici di dati (di qualsiasi tipo) e degli operatori statici. Fin qui il
meccanismo dei template mi sembra suffuciente a coprire le necessita'.
   Il problema nasce quando inserisco una classe per la visualizzazione
all'interno di un framework. Per evitare di 'templarizzare' (che brutto
termine! :-)) ) anche questa (e credo questo risolverebbe il problema)
devo ricorrere al puntatore alla classe base, che pero' introduce tutti i
problemi di cui sopra.
   A questo punto credo che investighero' la possibilita' di creare
effettivamente da template anche questa classe. Questo mi introdurra'
pero' tutta una serie di problemi legati all'architettura del framework
GUI che sto usando. Sperem ...
      Cris

problemi di cui sopra.
Questo non mi é chiaro!  Da dove viene fuori il *doppio* dispatch,
che é la radice del problema?  Mi pare che la visualizzazione sia
quella di UN oggetto (o matrice di oggetti), quindi riportabile al
meccanismo delle funzioni virtuali.  Perché devi visualizzare due
oggetti in modo dipendente dalla classe di ciascuno dei due?
Alex

 oggetti in modo dipendente dalla classe di ciascuno dei due?
   In effetti il discorso va preso un po' più alla larga. Il framework usa
un editor di interfaccia che crea elementi che vengono associati alle
classi tramite delle 'signatures' (unsigned long). Ora, quando costruisco
una window al suo interno inserisco degli elementi specificando la loro
signature (ed altri dati, dipendenti dal tipo di oggetto). Nel mio caso
avrei diversi oggetti, e quindi dovrei specificare diverse signatures (una
per ogni tipo di dato).
   A questo punto potrei creare un oggetto diverso per ogni tipo di dato.
Ognuno di questi oggetti in realtà e' costruito attraverso uno stesso
template. E questo risolverebbe il problema, se non che il tipo di oggetto
da visualizzare non potrebbe essere cambiato a run time (non una grossa
perdita, ma molesta). Rimarrebbe poi il problema della signature definita
più o meno in questo modo:
class DisplayableMatrix: public Pane
{
public:
      enum { class_ID = 'DsMa' };
      ...
};
Nel mio caso questo diverrebbe:
template<class DataType>
class DisplayableMatrix: public Pane
{
public:
      enum { class_ID = ??? };
      ...
};
lasciando il problema di come definire l'ID.
Spero di essere stato abbastanza chiaro. Non è facile sintetizzare in
poche righe l'essenza di un framework. :-)))
      Cris