can I/how can I use ptr_fun 
Author Message
 can I/how can I use ptr_fun

hi all,

I'm wrapping a c dll in a c++ wrapper and one the functions i'm wrapping requires a pointer to a function to be passed in.

the function needs to look like this : typedef long (*LPTEXTOUTPROC) (LPCSTR, DWORD)

so I have defined a member function like so:

long meclass::callback(LPCTSTR txt, DWORD flag)
{
...

Quote:
}

but I get compiler errors trying to pass that through to the lib:

error C2664: 'SetCallback' : cannot convert parameter 1 from 'long (meclass::*)(const char *,unsigned long)' to 'long (const char *,unsigned long)' There is no context in which this conversion is possible

Looking through some docs I find the stl::ptr_fun, which appears to do what I want, i.e. pass through a member function as a pointer to something, but I can't figure out how to use it!

please help

i'm using VC 6 sp5

TIA

bg



Sat, 09 Apr 2005 00:40:52 GMT  
 can I/how can I use ptr_fun

C-style callbacks must be standalone (non-member) functions, or static member functions. ptr_fun has nothing to do with it.

The problem is, a non-static member function is passed a hidden parameter accessible as a "this" pointer. That's how it knows which instance it is called on, and can access data members. Of course, your C DLL has no idea how to pass this hidden parameter.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat, and wrong." H.L. Mencken

  hi all,

  I'm wrapping a c dll in a c++ wrapper and one the functions i'm wrapping requires a pointer to a function to be passed in.

  the function needs to look like this : typedef long (*LPTEXTOUTPROC) (LPCSTR, DWORD)

  so I have defined a member function like so:

  long meclass::callback(LPCTSTR txt, DWORD flag)
  {
  ...
  }

  but I get compiler errors trying to pass that through to the lib:

  error C2664: 'SetCallback' : cannot convert parameter 1 from 'long (meclass::*)(const char *,unsigned long)' to 'long (const char *,unsigned long)' There is no context in which this conversion is possible

  Looking through some docs I find the stl::ptr_fun, which appears to do what I want, i.e. pass through a member function as a pointer to something, but I can't figure out how to use it!

  please help

  i'm using VC 6 sp5

  TIA

  bg



Sat, 09 Apr 2005 00:59:50 GMT  
 can I/how can I use ptr_fun

Quote:

> C-style callbacks must be standalone (non-member) functions, or static
> member functions. ptr_fun has nothing to do with it.

> The problem is, a non-static member function is passed a hidden
> parameter accessible as a "this" pointer. That's how it knows which
> instance it is called on, and can access data members. Of course, your C
> DLL has no idea how to pass this hidden parameter.

One pontential workaround is to create a static forwarding function to
handle delegation.  The obvious catch is that you need a function per
callee, but at least it works.  The simplest method would be something
like this:

class myclass
{
     static myclass* sm_inst;
public:
     myclass() { sm_inst = this; }
     static void myfwd( void* data ) {
         sm_inst->do( data );
     }

     void do( void* data ) { ... }

Quote:
};

Another alternative would be a standalone function or function object.
Combined with templates, you can make construction of such things pretty
simple.  It's really too bad C-style callbacks so often don't have a
parameter for some sort of state variable (a void ptr would be fine).
With something like this, you can just pass a pointer to a class
instance along with the initial call.  Makes life much simpler.


Sat, 09 Apr 2005 04:24:54 GMT  
 can I/how can I use ptr_fun

Quote:
> One pontential workaround is to create a static forwarding function to
> handle delegation.  The obvious catch is that you need a function per
> callee, but at least it works.  The simplest method would be something
> like this:

> class myclass
> {
>      static myclass* sm_inst;
> public:
>      myclass() { sm_inst = this; }
>      static void myfwd( void* data ) {
>          sm_inst->do( data );
>      }

>      void do( void* data ) { ... }
> };

How does this help if I have two instances of myclass alive at the same
time?
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Sat, 09 Apr 2005 05:03:03 GMT  
 can I/how can I use ptr_fun
On Mon, 21 Oct 2002 17:03:03 -0400, "Igor Tandetnik"

Quote:



>> One pontential workaround is to create a static forwarding function to
>> handle delegation.  The obvious catch is that you need a function per
>> callee, but at least it works.  The simplest method would be something
>> like this:

>> class myclass
>> {
>>      static myclass* sm_inst;
>> public:
>>      myclass() { sm_inst = this; }
>>      static void myfwd( void* data ) {
>>          sm_inst->do( data );
>>      }

>>      void do( void* data ) { ... }
>> };

>How does this help if I have two instances of myclass alive at the same
>time?

He addressed that further down his post - if you have a user void* (or
similar) parameter to the callback, you can pass the this pointer and
then cast.

Tom



Sat, 09 Apr 2005 21:06:47 GMT  
 can I/how can I use ptr_fun

Quote:
> On Mon, 21 Oct 2002 17:03:03 -0400, "Igor Tandetnik"



> >> One pontential workaround is to create a static forwarding function
to
> >> handle delegation.  The obvious catch is that you need a function
per
> >> callee, but at least it works.  The simplest method would be
something
> >> like this:

> >> class myclass
> >> {
> >>      static myclass* sm_inst;
> >> public:
> >>      myclass() { sm_inst = this; }
> >>      static void myfwd( void* data ) {
> >>          sm_inst->do( data );
> >>      }

> >>      void do( void* data ) { ... }
> >> };

> >How does this help if I have two instances of myclass alive at the
same
> >time?

> He addressed that further down his post - if you have a user void* (or
> similar) parameter to the callback, you can pass the this pointer and
> then cast.

The way I read it, Sean Kelly claims that the sample demonstrates one
function per callee. I only see one function per class, and in the
context of the thread I'd say that "callee" should mean an instance of
the class - that's what the OP wants his or her events routed to. The
class shown in the example is worse than useless IMHO - it behaves
unpredictably in the presence of more than one instance, and is likely
to crash the program real quick - sm_inst static variable easily ends up
holding a dangling pointer.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Sat, 09 Apr 2005 21:25:29 GMT  
 can I/how can I use ptr_fun

Quote:



>>On Mon, 21 Oct 2002 17:03:03 -0400, "Igor Tandetnik"



>>>>One pontential workaround is to create a static forwarding function

> to

>>>>handle delegation.  The obvious catch is that you need a function

> per

>>>>callee, but at least it works.  The simplest method would be

> something

>>>>like this:

>>>>class myclass
>>>>{
>>>>     static myclass* sm_inst;
>>>>public:
>>>>     myclass() { sm_inst = this; }
>>>>     static void myfwd( void* data ) {
>>>>         sm_inst->do( data );
>>>>     }

>>>>     void do( void* data ) { ... }
>>>>};

>>>How does this help if I have two instances of myclass alive at the

> same

>>>time?

>>He addressed that further down his post - if you have a user void* (or
>>similar) parameter to the callback, you can pass the this pointer and
>>then cast.

> The way I read it, Sean Kelly claims that the sample demonstrates one
> function per callee. I only see one function per class

Yup.  Sorry about that.  I digressed a bit and provided another solution
that works just fine if he's dealing with a singleton.  I didn't write
the code for what I was describing, but I did describe how to do it
(templates).

Quote:
> and in the
> context of the thread I'd say that "callee" should mean an instance of
> the class - that's what the OP wants his or her events routed to. The
> class shown in the example is worse than useless IMHO - it behaves
> unpredictably in the presence of more than one instance, and is likely
> to crash the program real quick - sm_inst static variable easily ends up
> holding a dangling pointer.

It was obviously a partial example.  At the very least, it should be
combined with a bit better management of the pointer and restricted to
one class instance (there are plenty of ways to do this, I occasionally
use the class Scott Meyers provided in one of his Effective C++ books).
  In my experience, this has generally been enough for the instances of
the MS library that don't provide a facility to pass a state variable.

I had been too lazy to implement the code I was describing, but I
remember having this conversation before so I looked it up on deja.
Turns out it was with you, Igor, a little over a year ago on this
newsgroup :).  In any case, since that appears to be outside the visible
window, this is the code I posted then, complete with example:

#include <iostream>

template<class cb_class,class cb_func,int uid>
class cb_proxy
{
public:
  cb_proxy( cb_class& cl, cb_func fn ) : m_uid( uid )
  {
      sm_class = &cl;
      sm_func = fn;
  }

  static void fwd_call( const char* ch )
  {
      (sm_class->*sm_func)( ch );
  }

private:
     static  cb_class* sm_class;
     static  cb_func  sm_func;
     const int    m_uid;

Quote:
};

template<class cb_class,class cb_func,int uid>
cb_class* cb_proxy<cb_class,cb_func,uid>::sm_class = NULL;

template<class cb_class,class cb_func,int uid>
cb_func cb_proxy<cb_class,cb_func,uid>::sm_func = NULL;

class foo
{
public:
     foo( int i ) : m_i( i ) {}
     void print( const char* ch ) { std::cout << ch << ' ' << m_i <<
std::endl; }
private:
     int m_i;

Quote:
};

int main()
{
     typedef void (foo::*cb_def)(const char*);
     foo f1( 1 ), f2( 2 );
     cb_proxy<foo,cb_def,1> cb1( f1, &foo::print );
     cb_proxy<foo,cb_def,2> cb2( f2, &foo::print );

     cb_proxy<foo,cb_def,1>::fwd_call( "hi" );
     cb_proxy<foo,cb_def,2>::fwd_call( "hi" );
     return( 0 );

Quote:
}

This is a bit kludgy, but it was more of a demonstration of principal
than anything else.  I imagine that the integer component could probably
be created and managed automatically, given a bit of creativity.
There's a series on generating bit-wise typeof in the recent issues of
CUJ that would probably be a good start.


Sun, 10 Apr 2005 00:15:44 GMT  
 can I/how can I use ptr_fun

Quote:
> #include <iostream>

> template<class cb_class,class cb_func,int uid>
> class cb_proxy
> {
> public:
>   cb_proxy( cb_class& cl, cb_func fn ) : m_uid( uid )
>   {
>       sm_class = &cl;
>       sm_func = fn;
>   }

>   static void fwd_call( const char* ch )
>   {
>       (sm_class->*sm_func)( ch );
>   }

> private:
>      static  cb_class* sm_class;
>      static  cb_func  sm_func;
>      const int    m_uid;
> };

The problem with this approach is as follows: no matter how clever you
are with generating template parameters, the number of different
instances of those static variables is fixed at compile time. If that's
sufficient, fine. But if you need to create sink objects on the fly, you
either need cooperation from the library calling the callback (passing
back some user-defined value where you can supply 'this' pointer) or you
need to generate assembly thunks, the way ATL does for window
procedures.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Sun, 10 Apr 2005 00:44:10 GMT  
 can I/how can I use ptr_fun

Quote:

> The problem with this approach is as follows: no matter how clever you
> are with generating template parameters, the number of different
> instances of those static variables is fixed at compile time. If that's
> sufficient, fine. But if you need to create sink objects on the fly, you
> either need cooperation from the library calling the callback (passing
> back some user-defined value where you can supply 'this' pointer) or you
> need to generate assembly thunks, the way ATL does for window
> procedures.

Exactly.  Or use my first solution (the singleton example) to act as an
interface to the underlying mechanism and serialize all access to it.
I've had to resort to doing this before and it really isn't so bad a
solution, provided the throughput hit is acceptable.  I agree that my
template example is far from an ideal solution, but for some cases it's
about as good as you can do.


Tue, 12 Apr 2005 03:13:44 GMT  
 
 [ 9 post ] 

 Relevant Pages 

1. Beginner [Q] Using Canned File Open/Save dialog

2. Determining what canned preprocessor symbols are available

3. Help with compiling a "canned" program

4. Canned Dialogs

5. Does C have a "canned" find function?

6. How to the Behavior of "canned" apps??

7. ptr_fun - template function problem.

8. ptr_fun() and static function

9. VC6: ptr_fun and/or pointer_to_binary_function can't build program

10. ptr_fun and functions returning void

11. Problem with ptr_fun

12. Using types in a different assembly given that the type may be used or not used

 

 
Powered by phpBB® Forum Software