Newsgroup: it.comp.lang.c++
Titolo: override di metodi virtuali con funzioni template

Saluti.
Come da oggetto quello che vorrei fare è la seguente
cosa:
#include <iostream>
struct RNG
{
  virtual float asClamped() = 0;
};
struct LCG: public RNG
{
  LCG() { }
  float asClamped() { return 0.6; }
};
struct base
{
  virtual float attemp_transition(RNG& rng) { return 0; }
};
struct derived: public base
{
  template<class Random> float attemp_transition(Random& rng)
  {
    return rng.asClamped();
  }
};
#include <iostream>
int main()
{
  LCG acg;
  derived d;
  std::cout << d.attemp_transition(acg) << '\n';
  RNG* rng = &acg;
  base* b = &d;
  std::cout << b->attemp_transition(*rng) << '\n';
}
L'idea è di poter sfruttare, a scelta, il 'polimorfismo a compile-time' o
quello a run-time.
Putroppo il codice così come è non funziona; devo esplicitamente aggiungere
il medodo:
float attemp_transition(RNG& rng)
{
  return attemp_transition<RNG>(rng);
}
Come mai? La versione che il compilatore instanzia automaticamente non va bene
per l'override? Non capisco perchè lo Standard specifichi questo comportamento.
La situazione è simile al caso del costruttore di copia template e, a dire il
vero, non capisco il perchè nemmeno in quel caso.
P.S. quale è la corretta traduzione in italiano per 'override'?
Saluti e grazie  Manlio Perillo


C'è da aggiungere che se invece faccio con il VCC 7 (beta 2):
template<class T> struct derived: public base
{
  template<class Random> float attemp_transition(Random& rng)
  {
    return rng.asClamped();
  }
};
Ottengo un errore : "Le funzioni template non possono essere virtuali"....
Manlio Perillo

Ottengo un errore : "Le funzioni template non possono essere virtuali"....
Questo sta scritto esplicitamente nello standard... (o per
lo meno era nel draft); ma lo standard cita un esempio che
mi sembra molto simile al codice che VC++7 si rifiuta di
compilare.
   14.5.2 Member Templates [temp.mem]
   ...
   3 A member function template shall not be virtual.
     [Example:
       template <class T> struct AA {
            template <class C>
              virtual void g(C);   // error
            virtual void f();      // OK
       };
     --end example]
   4 A specialization of a member function template
     does not override a virtual function from a
     base class.
     [Example:
        class B {
          virtual void f(int);
        };
        class D : public B {
          template <class T>
            void f(T); // does not override B::f(int)
 
          // overriding function that calls
          // the template instantiation
          void f(int i) { f<>(i); }
        };
      --end example]
Il perche' del divieto di avere metodi template virtuali
credo sia squisitamente tecnico: il compilatore deve
(deve ?) decidere la struttura e dimensione della VMT e
non potrebbe farlo se esistono funzioni virtuali template
senza analizzare tutto il progetto.
Il C++ e' stato pensato per essere compilabile un pezzo
alla volta (per agevolare la compilazione di progetti
molto grossi) e questa credo sia una delle conseguenti
limitazioni del linguaggio. Forse la definizione delle
VMT potrebbe essere posticipata a link time, ma con una
complessita' di linking C++ che probabilmente non si
desiderava (e il link diventerebbe qualcosa di piu' che
semplice "fix" di indirizzi come avviene per il C).
Andrea

 [CUT]
In effetti credevo che solo la funzione virtuale nella classe base
non potesse essere virtuale.
Comunque resta lo strano comportamento del VCC 7 (ma dato che è una beta..), il
quale si confonde nell'esempio:
// compila ma non fa l'override della funzione virtuale. Ok: standard
struct derived: public base
{
  template<class Random> float attemp_transition(Random& rng)
  {
    return rng.asClamped();
  }
;
// non compila!
template<class T> struct derived: public base
{
  template<class Random> float attemp_transition(Random& rng)
  {
    return rng.asClamped();
  }
}
A questo punto mi chiedo se, secondo lo standard, quest'ultimo esempio
dovrebbe compilare.


dovrebbe compilare.
Non vedo perche' non dovrebbe compilare (anche in questo
caso senza pero' fare l'override della funzione virtuale).
I template, una volta abbandonata la via principale delle
cose moooooooooooooolto semplici, sono ancora oggi secondo
me un campo minato per quanto riguarda la portabilita'.
Io recentemente ho implementato una classe che si occupa
di gestire una mappatura n-dimensionale (data una griglia
a n dimensioni di valori noti viene calcolato per
interpolazione il valore in un punto qualunque dello
spazio n-dimensionale; mi serviva per 5 dimensioni ma ho
deciso di affrontare il problema in modo generico invece
di andare di copia-incolla rendendo un parametro sia n
che il tipo interpolato -- le coordinate sono invece sempre
dei "double"). Nonostante dal punto di vista del linguaggio
C++ non ci sia nulla di complesso se paragonato alle capriole
di Alexandrescu ho fatto abbastanza fatica a trovare una
versione che compilasse e che facesse le stesse cose su
g++, BCC e VC++; purtroppo scendendo anche a compromessi
sul tipo di interfaccia da fornire.
Temo che a oggi il tempo di sviluppo di codice template
vada almeno con il quadrato del numero di compilatori
che vuoi compilino il tuo codice (specie se hai l'assurda
pretesa che oltre a compilare le diverse versioni facciano
tutte la stessa cosa :-) )
In un mondo ideale il tempo di sviluppo dovrebbe essere
O(1) ovvero indipendente dal numero di compilatori
... speriamo per il futuro...
Andrea

 ha scritto nel messaggio
news:3cc3a1e...@news.tin.it...

Anche io sto avendo molti problemi nell'implemetare una classe delegate
(come discusso tempo fa) che funzioni sia sul g++ che con il VCC.
In particolare il VCC 7 (beta 2) non gradisce che si prenda
l'indirizzo di una funzione template.
template<class T> void f(T a);
void (*pf)(int) = &f<int>;
Spero proprio che sia un problema della beta č non una non conformance
della versione 7.
Inoltre sempre il VCC 7 non supporta la specializzazione parziale dei
template ed č una 'gossa' deficienza.
Colgo l'occasione per una questione riguardo std::swap.
Tale funzione va specializzata o ne va fatto l'overload?
Che differenza c'č?
Saluti  Manlio Perillo

 Che differenza c'č?
vado a memoria perche` non ho il tempo di andare a controllare e quindi 
potrei sbagliarmi, ma lo standard proibisce al programmatore di definire 
funzioni, classi, variabili ecc., nel namespace std, quindi l'overload 
di std::swap e` di fatto non portabile. Al contrario lo standard 
permette esplicitamente la specializzazione dei template residenti nel 
namespace std, quindi non si pone neppure il problema: devi 
specializzare.
ciao Anto
-- 
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.73, higher than 99% of all previous test takers.
C Language: 3.79, higher than 92% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it

 specializzare.
Non sono del tutto convinto perche' non e' comunque possibile
specializzare parzialmente una funzione, quindi l'unico modo per
implementare std::swap() su una propria classe template e' scrivere un
overload.
Ciao,
Nicola

 overload.
beh, ma non e` necessario specializzare parzialmente, basta una 
specializzazione "normale":
class Prova { };
template<>
void std::swap<Prova>(Prova&, Prova&)  { }


 void std::swap<Prova>(Prova&, Prova&)  { }
Mi riferivo a qualcosa come:
template <class T> class MioContainer {};
template <class T>
void std::swap(MioContainer<T> &, MioContainer<T> &);
Ciao,
Nicola

 void std::swap(MioContainer<T> &, MioContainer<T> &);
La risposta e' qui:
http://groups.google.com/groups?selm=aaj2he%24a0h%241%40bcarh8ab.ca.nortel.com
:-(
Ciao,
Nicola

 ha scritto nel messaggio
news:3CCD14D3...@divalsim.it...

In effetti lo Stroustrup dice che una funzione si puň specializzare ma quello
che in effetti
fa č un overload ($13.5.2)
template<class T> void swap(vector<T>&, vector<T>&);
Lui la chiama specializzazione di swap.
Saluti  Manlio Perillo

 Lui la chiama specializzazione di swap.
che pero` se siamo nel namespace std e` illegale (almeno per noi poveri 
utenti): credo proprio che non ci sia soluzione, come ha gia` 
evidenziato Nicola.
Cmq, deviando un attimo dal discorso principale, mi e` venuto in mente 
un metodo per "simulare" la specializzazione parziale delle funzioni 
(anche se purtroppo non si puo` applicare a std::swap):
template<class T>
struct f_impl
{
  static void exec(T)  { ... }
};
template<class T>
struct f_impl<T*>
{
  static void exec(T*) { ... }
};
template<class T>
void f(T t)
{
  return f_impl<T>::exec(t);


 ha scritto nel messaggio
news:3CCE78AE...@divalsim.it...

Con il VCC ho fatto:
// dichiarazione
namespace std
{
    template <class T>
    void swap(MioContainer<T> &, MioContainer<T> &);
}
// definizione
template <class T>
void std::swap(MioContainer<T> &, MioContainer<T> &)
{
    // ...
}
e non mi ha fatto problemi.
Saluti  Manlio Perillo

 e non mi ha fatto problemi.
Anche se mi aspetto che funzioni su tutti i compilatori, e' tecnicamente
illegale, o meglio comportamento indefinito.
Ciao,
Nicola

 ha scritto nel messaggio
news:3CD24DE9...@divalsim.it...

Ma non è quello che fanno tutti i container della STL?
Ciao  Manlio Perillo

 Ma non è quello che fanno tutti i container della STL?
si, pero` loro possono ;-)
Lo standard dice che il programmatore non puo` aggiungere nulla 
all'interno del namespace std, ma ovviamente lo standard stessi puo` 
aggiungerci tutti i nomi che vuole...


 all'interno del namespace std, 
...salvo *specializzazioni* di template definite su tipi definiti
dall'utente.
Il problema e' che 
std::swap<pippo>(pippo &,pippo &);
e' una specializzazione, mentre
template <class T> std::swap(pluto<T> &,pluto<T> &);
e' un overload.
Ciao,
Nicola