Newsgroup: it.comp.lang.c++
Titolo: Lightweight functor

Ciao a tutti!
Il concetto di functor e' abbastanza noto, e se ne trovano un po' ovunque...
Quelli di boost mi sembrano fatti molto bene, ad esempio...
Io stavo cercando di costruirne uno per i fatti miei (molto naif tra
l'altro) perche' lo devo usare in un contesto un po' particolare, e vorrei
controllare in modo preciso quello che fa, quanto spazio occupa e
l'overhead che introduce...
L'idea di base, per incapsulare la chiamata ad un metodo di una classe (mi
basta questo in pratica) e' questa:
template < typename R, typename P >
class Method
  {
  private:
    class Generic {};
    typedef R (Generic::*MethodPtr)(P);
    typedef Generic* ClassPtr;
    ClassPtr ptrClass;
    MethodPtr ptrMethod;
  public:
    template < typename C >
    Method( C* pClass, R (C::*pMethod)(P) ) :
      ptrClass( reinterpret_cast<ClassPtr>(pClass) ),
      ptrMethod( reinterpret_cast<MethodPtr>(pMethod) )
      {}
    R operator()( P p ) { return ((*ptrClass).*(ptrMethod))(p); }
  };
E questo e' un esempio di utilizzo:
#include <iostream>
class Aclass
  {
  private:
    int fooBody(int x) { std::cout << ( x + y ) << std::endl; return 0; }
    int y;
  public:
    Method<int,int> foo;
    Aclass() : y(10), foo( this, &Aclass::fooBody ) {}
  };
int main()
  {
  Aclass a;
  a.foo(1);
  a.foo(2);
  }
Fatto e compilato con il gcc, mi sembra funzionare abbastanza bene;
l'overhead, rispetto ad una chiamata diretta, e' paragonabile (correggetemi
se sbaglio) ad una chiamata a metodo virtual.
Non sono del tutto sicuro che il trucco di forzare il cast a "Generic *" del
puntatore alla classe sia sempre lecito...
...puo' esistere secondo voi qualche caso (magari legato all'inheritance mi
vien da pensare) in cui questo puo' dare comportamenti inaspettati?
Rispetto ad altri metodi che ho visto, in questo modo riesco ad eliminare la
classe concreta (AClass) dai parametri template di Method, ed ho anche il
vantaggio di non allocare nulla dinamicamente. Infatti un altro modo di
farlo poteva essere una cosa di questo tipo (liberamente tratto dal libro
di Alexandrescu):
template < typename R, typename P >
class Method
  {
  private:
    BaseMethodImpl<R,P> impl;
  public:
    template < typename C >
    Method( C* pClass, R (C::*pMethod)(P) ) :
      impl( new MethodImpl<C,R,P>(pClass,pMethod) )
    {}
    R operator()( P p ) { return impl.call(p); }
    //...
  };
dove:
template < typename R, typename P >
class BaseMethodImpl
  {
  public:
    //...
    virtual R call( P p ) = 0;
  };
template < typename C, typename R, typename P >
class MethodImpl : public BaseMethodImpl
  {
  public:
    //...
    R call( P p ) { /* ... */ };
  };
Spero si capisca (no voglio dilungarmi troppo...) :-)
Grazie dell'aiuto!
Ciao.

 del puntatore alla classe sia sempre lecito...
Si è discusso, tra le altre cose, anche di questo problema, quando in 
questo NG si è parlato di possibili implementazioni in C++ dei "delegate" 
del C#, o delle "closure" di Delphi.
Prima di riaddentrarsi nella discussione suggerirei di dare uno sguardo ai 
thread interessati, iniziando, ad esempio, da questi due messaggi:
 
http://groups.google.com/groups?selm=3BB2EA9D.A7437071%40divalsim.it
http://groups.google.com/groups?selm=jC9i8.49080%24Ns4.2067286%40news2.tin.it
Max

 
http://groups.google.com/groups?selm=jC9i8.49080%24Ns4.2067286
40news2.tin.it
Grazie, in effetti questi due thread trattano proprio il mio problema...
Mi e' solo rimasto il dubbio amletico di scegliere tra una maggiore
efficienza e l'aderenza completa allo standard :-(
Probabilmente non trovero' la risposta :-)