Newsgroup: it.comp.lang.c++
Titolo: Problema con puntatore a funzione

Salve
Ho un problema che ho cercato di semplificare nel codice che segue:
- dichiaro una prima classe 'operazione' che contiene un puntatore ad
una funzione e una funzione di settaggio
- dichiaro una seconda classe 'base' che contiene 2 istanze alla
classe 'operazione'
- il costruttore della classe 'base' utilizza la funzione
operazione::Set(...) per assegnare i puntatori alle due funzioni Somma
e Differenza
- la funzione 'main' utilizza la sintassi
base.operazione.puntatore_alla_funzione per richiamare
Somma/Differenza
Il tutto non funziona!
Il compilatore (VC++ 5.0) mi segnala un errore nella funzione
operazione::Set: 
'cannot convert parameter 1 from 'int (__thiscall base::*)(int *,int
*)' to 'int (__cdecl *)(int *,int *)''
P.S. Ovviamente il prg originale e' scritto per win32...
Qualsiasi aiuto e' graditissimo, segue il sorgente:
//Classe OPERAZIONE
////////////////////
class operazione  
{
public:
	int	(* fp)(int* value1,	int* value2);
//Puntatore ad una funzione
	void	Set(int (*)(int* value1,	int* value2));	
};
void operazione::Set(int (*pointer_to_function)(int* value1,	int*
value2))
{
	fp = pointer_to_function;
}
//Classe BASE
//////////////
class base  
{
public:
	operazione	op[2];
	base	();
	//Funzioni di cui verra' passato il puntatore
	int		Somma		(int* value1,	int* value2);
	int		Differenza	(int* value1,	int* value2);
};
base::base()	//Costruttore
{
	op[0].Set(Somma);
	op[1].Set(Differenza);
}
int base::Somma( int* value1,	int* value2 ) 
{
	return (*value1 + *value2);
}
int base::Differenza( int* value1,	int* value2 ) 
{
	return (*value2 - *value1);
}
//MAIN
///////
void Main()
{
	int v1 = 5;
	int v2 = 3;
	base b;
	b.op[0].fp(&v1, &v2);	//Somma
	b.op[1].fp(&v1, &v2);	//Differenza
}

 op[1].Set(Differenza);
Stai cercando di passare un puntatore ad una funzione di una class (thiscall
convention) ad un puntatore
ad una funzione normale.
Somma e Differenza sono funzioni di una classe (thiscall convention).
int (* fp)(int* value1, int* value2) è un puntatore ad una funzione
'normale' (__cdecl convention).
Le funzioni di tipo 'thiscall' (solitamente le funzioni membro non statiche)
gestiscono in maniera automatica il trasferimento nello stack del puntatore
this.
Non so se esiste un sistema per convertire un puntatore a funzione thiscall
ad un puntatore a funzione __cdecl o se ci sia una possibilità di dichiarare
un puntatore a funzione membro.
Puoi però aggirare alla radice il problema cambiando la dichiarazione delle
funzioni Somma e Differenza nel seguente modo.
class base
{
public:
operazione op[2];
base ();
// Funzioni di cui verra' passato il puntatore
static int Somma (int* value1, int* value2);
static int Differenza (int* value1, int* value2);
};
Così il programma viene compilato tranquillamente.
Ovviamente va bene se questa modifica non altera le finalità del tuo
progetto.
Di più non so dirti.
Ciao
Porlock.

----- Original Message -----
From: "FeedBack" <feedba...@SPAMfeedbackgames.it>
Newsgroups: it.comp.lang.c++
Sent: Wednesday, September 20, 2000 9:52 AM
Subject: Problema con puntatore a funzione
[CUT]
Come ti ha già risposto Porlock, la sintassi per i puntatori
a funzione ed i puntatori a funzioni membro di una classe
è diversa.
Ti ha anche suggerito di rendere le funzioni Somma e Differenza
statiche (e penso sia la soluzione migliore).
Se hai la necessità di usare puntatori a funzioni membro
ecco come si procede.
Nota: ho usato i template perchè altrimenti credo che non si
possa risolvere.
Infatti la classe 'base' usa un array di 'operazione'
la quale a sua volta richiede che la classe 'base'
sia definita perchè usa puntatori a suoi membri.
Inoltre non capisco perchè come argomenti di Somma e Differenza
usi dei puntatori (ed anche non const).
Ecco il codice, spero i miei commenti bastino.
Nota: in due punti ho indicato che non sono sicuro
      al 100% della correttezza dell'azione.
//
// R è il tipo restituito dalla funzione,
// C è il tipo di classe di cui la funzione è membro
// e A è il tipo passato alla funzione
//
/* ossia con un esempio
   class C
   {
     public:
       R f(R a, R b);
   };
   un puntatore al metodo f di C si definisce:
   R(C::*p)(A, A) = &C::f;
   per usare tale funzione, si deve indicare l'oggetto:
   C c;
   (c->*p)(a, a);
*/
template<class R, class C, class A>
class operazione
{
  private:
    // puntatore ad una funzione membro di C che restituisce
    // un R ed accetta due A
    R(C::*pmf)(A, A);
    // puntatore alla classe per cui deve essere chiamata la
    // funzione
    C* c_;
  public:
    // operazione( R(C::*p)(A, A), C* c )
    // pmf(p), c_(c) {  }
    void Set( R(C::*p)(A, A), C* c ) { pmf = p; c_ = c; }
    // per applicare l'operazione
    R operator()(A first, A second)
    {
      return (c_->*pmf)(first, second);
    }
};
template<class R, class A> class base
{
  public:
    // ****** NON SONO SICURO SI POSSA USARE base QUI ******
    operazione<R, base, A> op[2];
    base()
    {
      // ******* NON SONO SICURO SI POSSA USARE this QUI *******
      op[0].Set(&base::Somma, this);
      op[1].Set(&base::Differenza, this);
    }
    // Funzioni di cui verra' passato il puntatore
    int Somma (int value1, int value2)
    {
      return value1 + value2;
    }
    int Differenza (int value1, int value2)
    {
      return value2 - value1;
    }
};
#include <iostream>
int main()
{
  int v1 = 5;
  int v2 = 3;
  base<int, int> b;
  std::cout << b.op[0](v1, v2) << '\n'; // Somma
  std::cout << b.op[1](v1, v2) << '\n'; // Differenza
}
P.S.  non riesco a capire la motivazione di questo
      tuo approccio.
Manlio Perillo

[MEGA CUT]













// Nota: l'implementazione di operazione non è safe, se ti scordi
//       di usare Set sono GUAI


       return value2 - value1;
sei sicuro?
Non dovrebbe essere value1 - value2?
[ERRATA MODE OFF]
Comunque ecco un modo a mio avviso piů lineare di
implementare la cosa:
namespace binop
{
  template<class T, template<class> class BinOp>
  struct binary_operation
  {
    static T apply(T a, T b) { return BinOp<T>::apply(a, b); }
  };
  template<class T> struct plus
  {
    static T apply(T a, T b) { return a + b; }
  };
  template<class T> struct minus
  {
    static T apply(T a, T b) { return a - b; }
  };
  *******************************************************
  Oppure:
  // dichiarata ma NON definita
  template<class T, class BinOp>
  struct binary_operation;
  struct plus {  };
  struct minus {  };
  // specializzazioni parziali
  template<class T> struct binary_operation<T, plus>
  {
    static T apply(T a, T b) { return a + b; }
  };
  template<class T> struct binary_operation<T, minus>
  {
    static T apply(T a, T b) { return a - b; }
  };
  ********************************************************
  (Personalmente preferisco la prima).
}
template<class T> class base
{
  public:
    typedef T (*binop_ptr)(T, T);
  private:
    binop_ptr op[2];
  public:
    base()
    {
      using namespace binop;
      op[0] = &binary_operation<T, plus>::apply;
      op[1] = &binary_operation<T, minus>::apply;
    }
    binop_ptr operator[](unsigned i) { return op[i]; }
};
// E' buona norma non esporre publicamente i membri di una
// classe
#include <iostream>
int main()
{
  int v1 = 5;
  int v2 = 3;
  base<int> b;
  std::cout << b[0](v1, v2) << '\n'; // Somma
  std::cout << b[1](v1, v2) << '\n'; // Differenza
}
Manlio Perillo