Jump to page: 1 2
Thread overview
Cannot use function as foreach aggregate.
Apr 04, 2007
Daniel Keep
Apr 04, 2007
BCS
Apr 04, 2007
Lutger
Apr 05, 2007
BCS
Apr 06, 2007
BCS
Apr 06, 2007
BCS
Apr 04, 2007
Russell Lewis
Apr 05, 2007
Downs
April 04, 2007
So, I've just discovered that you can't use function pointers as the aggregate of a foreach.  To put it mildly: this sucks.

Basically I have a bunch of module-level functions used to iterate over some global state private to that module.  So, two questions:

1. Is this a bug?  If it's not, why can we use delegates but not function pointers?

2. What's the cleanest way to wrap a function pointer in a delegate?

	-- Daniel

-- 
int getRandomNumber()
{
    return 4; // chosen by fair dice roll.
              // guaranteed to be random.
}

http://xkcd.com/

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/
April 04, 2007
"Daniel Keep" <daniel.keep.lists@gmail.com> wrote in message news:ev07p5$17u9$1@digitalmars.com...
>
> So, I've just discovered that you can't use function pointers as the aggregate of a foreach.  To put it mildly: this sucks.
>
> Basically I have a bunch of module-level functions used to iterate over some global state private to that module.  So, two questions:
>
> 1. Is this a bug?  If it's not, why can we use delegates but not function pointers?
>
> 2. What's the cleanest way to wrap a function pointer in a delegate?

I don't know if it's the cleanest but it works well.

RetType delegate(Args) ToDelegate(RetType, Args...)(RetType function(Args)
func)
{
    struct S
    {
        RetType function(Args) func;

        RetType callMe(Args args)
        {
            return func(args);
        }
    }

    S* s = new S;
    s.func = func;
    return &s.callMe;
}



April 04, 2007
Jarrett Billingsley wrote:
> "Daniel Keep" <daniel.keep.lists@gmail.com> wrote in message news:ev07p5$17u9$1@digitalmars.com...
> 
>>So, I've just discovered that you can't use function pointers as the
>>aggregate of a foreach.  To put it mildly: this sucks.
>>
>>Basically I have a bunch of module-level functions used to iterate over
>>some global state private to that module.  So, two questions:
>>
>>1. Is this a bug?  If it's not, why can we use delegates but not
>>function pointers?
>>
>>2. What's the cleanest way to wrap a function pointer in a delegate?
> 
> 
> I don't know if it's the cleanest but it works well.
> 

I can't help but wonder if this works.

template ToDelegate(RetType, RetType function(Args) func, Args...)
{
    struct S
    {
        static S s
        RetType callMe(Args args)
        {
            return func(args);
        }
    }
    alias &S.s.callMe ToDelegate;
}
April 04, 2007
BCS wrote:
 > I can't help but wonder if this works.
> 
> template ToDelegate(RetType, RetType function(Args) func, Args...)
> {
>     struct S
>     {
>         static S s
>         RetType callMe(Args args)
>         {
>             return func(args);
>         }
>     }
>     alias &S.s.callMe ToDelegate;
> }

Perhaps it could be simplified to this:

ReturnType!(typeof(func)) delegate (A)
toDelegate(alias func, A = ParameterTypeTuple!(typeof(func)) )()
{	
	return ( A args) { return func(args); } ;
}

But it seems there is a bug with type tuples in delegate literals, which also affects your example. This can be made to work though with string mixins, expanding the tuples to a parameter list.
April 04, 2007
Jarrett Billingsley wrote:
> RetType delegate(Args) ToDelegate(RetType, Args...)(RetType function(Args) func)
> {
>     struct S
>     {
>         RetType function(Args) func;
> 
>         RetType callMe(Args args)
>         {
>             return func(args);
>         }
>     }
> 
>     S* s = new S;
>     s.func = func;
>     return &s.callMe;
> }

What you give above is the good, general solution, which allows you to save the resulting delegate, or return it from the function, or whatever.  But in cases where the delegate won't be used outside of the current function, it's simpler to use a delegate literal:

void myFunc() {
  int function(int delegate(inout Type)) myAggregateFunc = <whatever>;
  int delegate(int delegate(inout Type)) myAggregateDelegate =
        delegate int(int delegate(inout Type) dg)
                { return myAggregateFunc(dg); }

  foreach(Type myVar; myAggregateDelegate)
      { <body> }
}
April 05, 2007
"BCS" <BCS@pathlink.com> wrote in message news:ev0i44$2io$5@digitalmars.com...
> Jarrett Billingsley wrote:
>
> I can't help but wonder if this works.
>
> template ToDelegate(RetType, RetType function(Args) func, Args...)
> {
>     struct S
>     {
>         static S s
>         RetType callMe(Args args)
>         {
>             return func(args);
>         }
>     }
>     alias &S.s.callMe ToDelegate;
> }

Not quite.. you can't alias addresses, and I don't think you can pass function pointers as template arguments (though I might be wrong).

Though using your idea of a single static instance of the struct, my function can then become:

RetType delegate(Args) ToDelegate(RetType, Args...)(RetType function(Args)
func)
{
    struct S
    {
        static S s;
        static RetType function(Args) func;

        RetType callMe(Args args)
        {
            return func(args);
        }
    }

    S.func = func;
    return &S.s.callMe;
}

Which is pretty sweet, as it no longer requires a heap allocation with each call.


April 05, 2007
Jarrett Billingsley wrote:
> 
> Not quite.. you can't alias addresses, and I don't think you can pass function pointers as template arguments (though I might be wrong).
> 
> Though using your idea of a single static instance of the struct, my function can then become:
> 
> RetType delegate(Args) ToDelegate(RetType, Args...)(RetType function(Args) func)
> {
>     struct S
>     {
>         static S s;
>         static RetType function(Args) func;
> 
>         RetType callMe(Args args)
>         {
>             return func(args);
>         }
>     }
> 
>     S.func = func;
>     return &S.s.callMe;
> }
> 
> Which is pretty sweet, as it no longer requires a heap allocation with each call. 
> 
> 

I don't think that will work. It will only allow one delegate per function type.

int foo(int i){return 1;}
int bar(int i){return 2;}

auto a = ToDelegate!(int, int)(foo);
auto b = ToDelegate!(int, int)(bar); // stomps on a;

a(1); // should return 2 when 1 is expected


also it occurs to me that there is no reason that the addressOf is needed. If functions as args works (I think it does) then this should work:

template ToDelegate(RetType, RetType function(Args) func, Args...)
{
    struct S
    {
        static S s
        RetType callMe(Args args)
        {
            return func(args);
        }
    }
    alias S.s.callMe ToDelegate;
}

if that doesn't work than this might:

template ToDelegate(RetType, alias func, Args...)

but it might have problem with overloaded functions.
April 05, 2007
"BCS" <BCS@pathlink.com> wrote in message news:ev379f$1ccm$1@digitalmars.com...
>
> I don't think that will work. It will only allow one delegate per function type.

Yeah, you're right; I forgot that I didn't use an alias template parameter so it would be based on signature, not name.

> also it occurs to me that there is no reason that the addressOf is needed. If functions as args works (I think it does) then this should work:
>
> template ToDelegate(RetType, RetType function(Args) func, Args...)
> {
>     struct S
>     {
>         static S s
>         RetType callMe(Args args)
>         {
>             return func(args);
>         }
>     }
>     alias S.s.callMe ToDelegate;
> }

You can't alias expressions.  It has to be a function:

template ToDelegate(alias func)
{
    ReturnType!(func) delegate(ParameterTypeTuple!(func)) ToDelegate()
    {
        struct S
        {
            static S s;
            ReturnType!(func) callMe(ParameterTypeTuple!(func) args)
            {
                return func(args);
            }
        }

        return &S.s.callMe;
    }
}

...

int foo(int i){return 1;}
int bar(int i){return 2;}

...

auto a = ToDelegate!(foo);
auto b = ToDelegate!(bar);

writefln(a(1));
writefln(a(2));


April 05, 2007
Daniel Keep wrote:

> 2. What's the cleanest way to wrap a function pointer in a delegate?
> 

Okay, so it's not the cleanest way, and it's not automatic either, but it's easy as heck.

import std.stdio;
bool test(int e, float f) { return true; }
void main() { auto dg=(int e, float f) { return test(e, f); }; dg(4, 3.14159); writefln(typeid(typeof(dg))); }
April 06, 2007
Jarrett Billingsley wrote:
> 
> You can't alias expressions.  It has to be a function:
> 
> template ToDelegate(alias func)
> {
>     ReturnType!(func) delegate(ParameterTypeTuple!(func)) ToDelegate()
>     {
>         struct S
>         {
>             static S s;
>             ReturnType!(func) callMe(ParameterTypeTuple!(func) args)
>             {
>                 return func(args);
>             }
>         }
> 
>         return &S.s.callMe;
>     }
> }

Of course this all only works for statically known functions. If that isn't the case then the original solution is needed.

OTOH this might work

template ToDelegate(alias func)
{
 ReturnType!(func) delegate(ParameterTypeTuple!(func)) ToDelegate()
 {
  struct S
  {
   ReturnType!(func) callMe(ParameterTypeTuple!(func) args)
   {
    return(cast(typeof(func))cast(void*)this)(args);
   }
  }
  return &((cast(S*)cast(void*)&func).callMe);
 }
}

I'd have to play with it but the same thing could be done for a dynamic pointer just with a few things moved around.


Ohh, I'd so fire anyone who tried to get me to pay them for writing that.
« First   ‹ Prev
1 2