Thread overview
Aliasing current function template instance
May 01, 2020
Jean-Louis Leroy
May 01, 2020
Jean-Louis Leroy
May 01, 2020
Simen Kjærås
May 01, 2020
Adam D. Ruppe
May 01, 2020
Jean-Louis Leroy
May 01, 2020
Is it possible, inside a function template, to create an alias to the instantiated function? IOW the equivalent of __FUNCTION__, but yielding an alias?

The closest I came is:

  import std.string;
  import std.traits;

  void foo(T)(lazy T)
  {
    mixin(
      "alias thisFunction = ",
      __FUNCTION__[0..__FUNCTION__.lastIndexOf('.')],
      ";");
    pragma(msg, Parameters!thisFunction);
  }

  void main()
  {
    foo(0);
    foo("");
  }

  dmd -c aliasthisfunction.d
  (lazy int)
  (lazy string)

...but (unsurprisingly) this fails in presence of overloads. I.e. if I throw in:

  void foo(T)(int, T);

...then I get:

  aliasthisfunction.d(6): Error: template `aliasthisfunction.foo` matches more than one template declaration:
  aliasthisfunction.d(4):     `foo(T)(lazy T)`
  and
  aliasthisfunction.d(20):     `foo(T)(int, T)`
  ...

Something I have overlooked? Any ideas?

May 01, 2020
On 5/1/20 4:28 PM, Jean-Louis Leroy wrote:

> Something I have overlooked? Any ideas?
> 

This trick works. No idea who came up with it:

alias thisFunction = __traits(parent, {});

-Steve
May 01, 2020
On Friday, 1 May 2020 at 20:43:05 UTC, Steven Schveighoffer wrote:
> On 5/1/20 4:28 PM, Jean-Louis Leroy wrote:
>
>> Something I have overlooked? Any ideas?
>> 
>
> This trick works. No idea who came up with it:
>
> alias thisFunction = __traits(parent, {});
>
> -Steve

I think I get the idea. Alas it doesn't work inside a function template, because it returns the template, not the instance:

 void foo(T)(lazy T)
 {
   alias thisFunction = __traits(parent, {});
   pragma(msg, thisFunction.stringof);
   //pragma(msg, Parameters!thisFunction); // later
 }

 void main()
 {
   foo(0);
   foo("");
 }

prints:

  foo(T)(lazy T)
  foo(T)(lazy T)

Uncommenting the line that is (more or less) my real goal:

aliasthisfunction.d(7): Error: template instance `std.traits.Parameters!(foo)` does not match template declaration `Parameters(func...)`
  with `func = (foo(T)(lazy T))`
  must satisfy the following constraint:
`       isCallable!func`

May 01, 2020
On Friday, 1 May 2020 at 20:28:58 UTC, Jean-Louis Leroy wrote:
> Is it possible, inside a function template, to create an alias to the instantiated function? IOW the equivalent of __FUNCTION__, but yielding an alias?
>
> The closest I came is:
>
>   import std.string;
>   import std.traits;
>
>   void foo(T)(lazy T)
>   {
>     mixin(
>       "alias thisFunction = ",
>       __FUNCTION__[0..__FUNCTION__.lastIndexOf('.')],
>       ";");
>     pragma(msg, Parameters!thisFunction);
>   }
>
>   void main()
>   {
>     foo(0);
>     foo("");
>   }
>
>   dmd -c aliasthisfunction.d
>   (lazy int)
>   (lazy string)
>
> ...but (unsurprisingly) this fails in presence of overloads. I.e. if I throw in:
>
>   void foo(T)(int, T);
>
> ...then I get:
>
>   aliasthisfunction.d(6): Error: template `aliasthisfunction.foo` matches more than one template declaration:
>   aliasthisfunction.d(4):     `foo(T)(lazy T)`
>   and
>   aliasthisfunction.d(20):     `foo(T)(int, T)`
>   ...
>
> Something I have overlooked? Any ideas?

This should work:

alias context(alias a) = __traits(parent, a);

void fun() {
    alias ctx = context!({})();
}

{} becomes a lambda inside fun(), so it's parent is fun(). The same could be done by introducing a symbol explicitly, but that pollutes the namespace. This template works inside functions, methods, lambdas, modules, structs, classes and interfaces.

--
  Simen
May 01, 2020
On Friday, 1 May 2020 at 20:28:58 UTC, Jean-Louis Leroy wrote:
> Something I have overlooked? Any ideas?

There's an old rule, that I can't find in the spec anymore but I'm still pretty sure it is there, where taking the address of a template inside a template yields the current instantiation.

Then you can fetch the type of that and do some reflection off. So try this in your test rig:

   pragma(msg, Parameters!(typeof(&foo)));

This rule was in there to ease callbacks and recursive functions iirc but it can also work with you thanks to typeof turning the runtime address back into a compile time alias.
May 01, 2020
On Friday, 1 May 2020 at 21:05:17 UTC, Adam D. Ruppe wrote:
> On Friday, 1 May 2020 at 20:28:58 UTC, Jean-Louis Leroy wrote:
>> Something I have overlooked? Any ideas?
>
> There's an old rule, that I can't find in the spec anymore but I'm still pretty sure it is there, where taking the address of a template inside a template yields the current instantiation.
>
> Then you can fetch the type of that and do some reflection off. So try this in your test rig:
>
>    pragma(msg, Parameters!(typeof(&foo)));
>
> This rule was in there to ease callbacks and recursive functions iirc but it can also work with you thanks to typeof turning the runtime address back into a compile time alias.

It looks like it does the trick. Thanks! Trying to add support for method templates to openmethods.