Newsgroup: it.comp.lang.c++
Titolo: Passaggio di  un puntatore a metodo (error C2664)

Ciao non riesco a risolvere questo problema:
Ho una classe A (che non posso modificare) la quale ha un metodo "fun"
che prende un puntatore a funzione, io voglio chiamare questo metodo
da un oggetto B passandogli come argomento l'indirizzo di un metodo di
B "funStima". (questo che segue è un esempio semplificato della
situazione in cui mi trovo)
/*************** Classe A data non modificabile
**********************************/
class A{
   int val1;
   int val2;
public:
  A():val1(10),val2(10){}
  ~A(){}
  int fun(int (fun)(int a, int b)){
     return((*fun)(val1,val2));
  }
};
/*********** Classe B quella che sto scrivendo io che ***********
*************deve invocare il metodo "fun" di A passandogli ****
*************un proprio metodo ************************************/
class B{
public:
  int res;
  int k;
  B(){res=0;k=11;}
  ~B(){}
    int funStima(int a, int b){
      res=(a+b+k);
    return res;
    }
   int run(void){
     A f;
     return (f.fun(&B::funStima));
  }
};
/*************************************************/
int main(){
    B ma;
    printf("%d",ma.run());
return 0;
}
/*************************************************/
Questo è l'errore che mi dà:
Error 1 error C2664: 'A::fun:  cannot convert parameter 1 from 'int
(__thiscall B::* )(int,int)'  to 'int (__cdecl *)(int,int)'
Una soluzione che ho trovato è quella di dichiarare "funStima" come
statica ed ovviamente anche "res" e "k". Ma questa soluzione non è
molto pulita e mi chiedevo se c'era qualche soluzione migliore. Ed
eventualmente se si potesse modificare A come si potrebbe modificare
per fare in modo che invece di prendere un puntatore a funzione stile
C, possa prendere un puntatore ad un metodo?

 C, possa prendere un puntatore ad un metodo?
In questo caso la funzione deve prevedere un parametro di tipo
            int (B::* )(int,int)
Ovviamente, la funzione dovrà ricevere anche un puntatore o un riferimento a
un'istanza di B.
Nel tuo caso, A::fun potrebbe diventare:
 
 int fun( B* obj,  int (B::* fun )(int a, int b) ) {
     return (obj->*fun)(val1,val2) ;
   }
E B::run diventerebbe:
 
  int run(void){
     A f;
     return (f.fun(this,&B::funStima));
  }
In alternativa, potresti usare "boost::bind" (GIYF). 
Max

 wrote:

Ok, così però la funzione "fun" può essere invocata solo da oggetti di
tipo B visto che la dichiarazione di fun è:
int fun( B* obj,  int (B::* fun )(int a, int b) ) ;  come si fà a fare
in modo che possa essere chiamata anche da altri oggetti?
Grazie.
Ciao

 - Show quoted text -
Forse ho trovato:
template <class T>
class A{
    int val1;
    int val2;
public:
   A():val1(10),val2(10){}
   ~A(){}
   int fun(T* obj,int (T:: *fun)(int a, int b)){
        return (obj->*fun)(val1,val2) ;
   }
};
Ciao.

 template <class T>
Se l'unico posto in cui ti serve che sia templatico è la funzione, rendi
templatica la funzione e non tutta la classe.
-- 
-riko

  ...
Se usassi "boost::bind", potresti definire A cosě:
 class A{
     int val1;
     int val2;
 public:
    A():val1(10),val2(10){}
    ~A(){}
    template< typename Func > int fun( Func f ){
         return f(val1,val2) ;
    }
 };
..e implementare B::run cosě:
 
 int run(void){
     A f;
     return f.fun( boost::bind( &B::funStima, this, _1, _2 ) );
  }
 
Il vantaggio č che ora A::func puň ricevere come argomento anche una
funzione ordinaria (come nella versione iniziale).
Max