Any workaround for "closures are not yet supported in CTFE"?

Petar Petar
Wed Dec 8 08:07:59 UTC 2021


On Wednesday, 8 December 2021 at 07:55:55 UTC, Timon Gehr wrote:
> On 08.12.21 03:05, Andrey Zherikov wrote:
>> On Tuesday, 7 December 2021 at 18:50:04 UTC, Ali Çehreli wrote:
>>> I don't know whether the workaround works with your program 
>>> but that delegate is the equivalent of the following struct 
>>> (the struct should be faster because there is no dynamic 
>>> context allocation). Note the type of 'dg' is changed 
>>> accordingly:
>> 
>> The problem with struct-based solution is that I will likely 
>> be stuck with only one implementation of delegate (i.e. opCall 
>> implementation). Or I'll have to implement dispatching inside 
>> opCall based on some "enum" by myself which seems weird to me. 
>> Do I miss anything?
>
> This seems to work, maybe it is closer to what you are looking 
> for.
>
> ```d
> import std.stdio, std.traits, core.lifetime;
>
> struct CtDelegate(R,T...){
>     void* ctx;
>     R function(T,void*) fp;
>     R delegate(T) get(){
>         R delegate(T) dg;
>         dg.ptr=ctx;
>         dg.funcptr=cast(typeof(dg.funcptr))fp;
>         return dg;
>     }
>     alias get this;
>     this(void* ctx,R function(T,void*) fp){ this.ctx=ctx; 
> this.fp=fp; }
>     R opCall(T args){ return fp(args,ctx); }
> }
>
> auto makeCtDelegate(alias f,C)(C ctx){
>     static struct Ctx{ C ctx; }
>     return 
> CtDelegate!(ReturnType!(typeof(f)),ParameterTypeTuple!f[0..$-1])(new Ctx(forward!ctx),
>           (ParameterTypeTuple!f[0..$-1] args,void* ctx){ auto 
> r=cast(Ctx*)ctx; return f(r.ctx,forward!args); });
> }
>
> struct A{
>     CtDelegate!void[] dg;
> }
>
> auto createDelegate(string s){
>     return makeCtDelegate!((string s){ s.writeln; })(s);
> }
>
> A create(){
>     A a;
>     a.dg ~= createDelegate("hello");
>     a.dg ~= createDelegate("buy");
>     return a;
> }
>
>
> void main(){
>     static a = create();
>     foreach(dg; a.dg)
>         dg();
> }
>
> ```

Incidentally, yesterday I played with a very similar solution. 
Here's my version:

https://run.dlang.io/gist/PetarKirov/f347e59552dd87c4c02d0ce87d0e9cdc?compiler=dmd


```d
interface ICallable
{
     void opCall() const;
}

auto makeDelegate(alias fun, Args...)(auto ref Args args)
{
     return new class(args) ICallable
     {
         Args m_args;
         this(Args p_args) { m_args = p_args; }
         void opCall() const { fun(m_args); }
     };
}

alias Action = void delegate();

Action createDelegate(string s)
{
     import std.stdio;
     return &makeDelegate!((string str) => writeln(str))(s).opCall;
}

struct A
{
     Action[] dg;
}

A create()
{
     A a;
     a.dg ~= createDelegate("hello");
     a.dg ~= createDelegate("buy");
     return a;
}

void main()
{
     enum a = create();
     foreach(dg; a.dg)
         dg();
}
```


More information about the Digitalmars-d-learn mailing list