View mode: basic / threaded / horizontal-split · Log in · Help
November 01, 2010
How to use a member function (delegate) as a function pointer
Hello.  I'm new to D. It's been a long time since I've coded anything with
classes.  Please excuse my ignorance.

Here's a very simplified version of what I'm trying to do:

import std.c.linux.linux;
import std.stdio;
class FOO
   {
   this()
       {
       sa.sa_handler = &handler;
       sigemptyset(&sa.sa_mask);
       sa.sa_flags = SA_RESTART;
       sigaction(SIGALRM, &sa, null);
       }

   ~this()
       {
       sa.sa_handler = SIG_DFL;
       sigemptyset(&sa.sa_mask);
       sa.sa_flags = SA_RESTART;
       sigaction(SIGALRM, &sa, null);
       }

   private:
   sigaction_t sa;

   void handler(int signal)
       {
       writeln("Got an alarm signal.");
       }
   }


Is there a way to do it without removing handler() from the class?  When I try
compiling, I get: Error: cannot implicitly convert expression (&this.handler)
of type void delegate(int signal) to void C function(int).

Thank you,
- Peter
November 01, 2010
Re: How to use a member function (delegate) as a function pointer
On Mon, 01 Nov 2010 05:27:06 +0300, Peter Federighi <pfederighi@yahoo.com>  
wrote:

> Hello.  I'm new to D. It's been a long time since I've coded anything  
> with
> classes.  Please excuse my ignorance.
>
> Here's a very simplified version of what I'm trying to do:
>
> import std.c.linux.linux;
> import std.stdio;
> class FOO
>     {
>     this()
>         {
>         sa.sa_handler = &handler;
>         sigemptyset(&sa.sa_mask);
>         sa.sa_flags = SA_RESTART;
>         sigaction(SIGALRM, &sa, null);
>         }
>
>     ~this()
>         {
>         sa.sa_handler = SIG_DFL;
>         sigemptyset(&sa.sa_mask);
>         sa.sa_flags = SA_RESTART;
>         sigaction(SIGALRM, &sa, null);
>         }
>
>     private:
>     sigaction_t sa;
>
>     void handler(int signal)
>         {
>         writeln("Got an alarm signal.");
>         }
>     }
>
>
> Is there a way to do it without removing handler() from the class?  When  
> I try
> compiling, I get: Error: cannot implicitly convert expression  
> (&this.handler)
> of type void delegate(int signal) to void C function(int).
>
> Thank you,
> - Peter

No, unfortunately not. A delegate is a function pointer PLUS 'this'. The C  
API you are using allows providing function only, without a context. As  
such, you need to store 'this' pointer somewhere else. It is usually done  
by means of of a special userData variable which is additionally passed to  
the callback (looks like we are out of luck this time), or storing it in a  
global variable:

Foo foo;
void externalHandler(int signal)
{
    assert(foo !is null);
    foo.handler(signal);
}

class Foo
{
    this() {
        assert(foo is null);
        foo = this;
        sa.sa_handler = &externalHandler;
        // ...
    }
    ~this() {
        assert(foo is this);
        foo = null;
        // ...
    }
    // ...
}
November 01, 2010
Re: How to use a member function (delegate) as a function pointer
"Peter Federighi" <pfederighi@yahoo.com> wrote in message 
news:ial8hq$2137$1@digitalmars.com...
> Is there a way to do it without removing handler() from the class?  When I 
> try
> compiling, I get: Error: cannot implicitly convert expression 
> (&this.handler)
> of type void delegate(int signal) to void C function(int).

Yes, but it requires some nasty code.

(Not tested on anything except windows)
http://yebblies.com/thunk.d

(Also not tested)

import yebblies.thunk.d;
import std.c.linux.linux;
import std.stdio;
class FOO
   {
   this()
       {
       th = thunk!"C"(&handler);
       sa.sa_handler = th.ptr;
       sigemptyset(&sa.sa_mask);
       sa.sa_flags = SA_RESTART;
       sigaction(SIGALRM, &sa, null);
       }

   ~this()
       {
       sa.sa_handler = SIG_DFL;
       sigemptyset(&sa.sa_mask);
       sa.sa_flags = SA_RESTART;
       sigaction(SIGALRM, &sa, null);
       }

   private:
   sigaction_t sa;
   typeof(thunk!"C"(&handler)) th;

   void handler(int signal)
       {
       writeln("Got an alarm signal.");
       }
   }

It basically gets around the restriction by writing some code into memory 
that passes the delegate params in unused registers.  I don't even know if 
the page allocation code works on anything except windows.

Daniel
Top | Discussion index | About this forum | D home