www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to get number of parameters in lambda?

reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
What should I use to get number of lambda arguments? Like get 2 
for "(arg1, arg2) {}". std.traits.Parameters doesn't work because 
isCallable returns false.

     alias f = (arg1, arg2) {};

     writeln(isCallable!f);   // prints false


Specifying argument types works, e.g. isCallable returns true for 
(int arg1, int arg2) {}, but I'm looking for a solution for 
type-less lambdas.
Mar 08 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 8 March 2021 at 23:07:18 UTC, Andrey Zherikov wrote:
 What should I use to get number of lambda arguments? Like get 2 
 for "(arg1, arg2) {}". std.traits.Parameters doesn't work 
 because isCallable returns false.

     alias f = (arg1, arg2) {};

     writeln(isCallable!f);   // prints false


 Specifying argument types works, e.g. isCallable returns true 
 for (int arg1, int arg2) {}, but I'm looking for a solution for 
 type-less lambdas.
Typeless lambdas are templates, and there's no way to examine the arguments of a template function without first instantiating it, so I'm afraid you're out of luck. What's the larger problem you're trying to solve here?
Mar 08 2021
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Tuesday, 9 March 2021 at 01:38:52 UTC, Paul Backus wrote:
 What's the larger problem you're trying to solve here?
Just to make things simple: I have a 'caller' that calls some function provided as an alias template argument and I want to support different number of arguments (purpose is to provide additional parameters if 'f' supports): void caller(alias f)() { static if(/*one parameter*/) f(1); else static if(/*two parameters*/) f(1, 2); } I understand that types are not available since they are undefined until instantiation. But why can't I get argument count? Is it possible that it can change during instantiation?
Mar 08 2021
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 9 March 2021 at 02:24:07 UTC, Andrey Zherikov wrote:
 On Tuesday, 9 March 2021 at 01:38:52 UTC, Paul Backus wrote:
 What's the larger problem you're trying to solve here?
Just to make things simple: I have a 'caller' that calls some function provided as an alias template argument and I want to support different number of arguments (purpose is to provide additional parameters if 'f' supports): void caller(alias f)() { static if(/*one parameter*/) f(1); else static if(/*two parameters*/) f(1, 2); }
If you know the arguments you want to call the function with, the easiest way to check if you can do it is with __traits(compiles): static if (__traits(compiles, f(1))) f(1); else static if (__traits(compiles, f(1, 2))) f(2);
 I understand that types are not available since they are 
 undefined until instantiation. But why can't I get argument 
 count? Is it possible that it can change during instantiation?
Yes, it's possible. For example: template fun(T) { static if (is(T == int)) { void fun(T a, T b) { /* ... */ } } else { void fun(T a) { /* ... */ } } } Of course, code like this is rare in practice, but because it's technically possible, the compiler can't assume *anything* about a template function before it's been instantiated.
Mar 08 2021
next sibling parent Paul Backus <snarwin gmail.com> writes:
On Tuesday, 9 March 2021 at 03:08:14 UTC, Paul Backus wrote:
 else static if (__traits(compiles, f(1, 2)))
     f(2);
Typo; this should of course say `f(1, 2)`.
Mar 08 2021
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Tuesday, 9 March 2021 at 03:08:14 UTC, Paul Backus wrote:
 Yes, it's possible. For example:

 template fun(T) {
It'd be nice if we could at least get the arity of a template, then perhaps speculatively instantiate it and reflect on the eponymous function then. (that's a lot of jargon lol but like some kind of reflection over template parameters is definitely possible... just the compiler doesn't offer any facilities for it at all. Then once you're past that layer you can start trying other things.)
Mar 08 2021
prev sibling parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Tuesday, 9 March 2021 at 03:08:14 UTC, Paul Backus wrote:
 If you know the arguments you want to call the function with, 
 the easiest way to check if you can do it is with 
 __traits(compiles):

 static if (__traits(compiles, f(1)))
     f(1);
 else static if (__traits(compiles, f(1, 2)))
     f(2);
Yes, I can do some magic with this.
 I understand that types are not available since they are 
 undefined until instantiation. But why can't I get argument 
 count? Is it possible that it can change during instantiation?
Yes, it's possible. For example: template fun(T) { static if (is(T == int)) { void fun(T a, T b) { /* ... */ } } else { void fun(T a) { /* ... */ } } } Of course, code like this is rare in practice, but because it's technically possible, the compiler can't assume *anything* about a template function before it's been instantiated.
In case of function template this is possible but the original question was about lambdas. There is no way that lambda can change number of parameters during instantiation, am I right?
Mar 09 2021
parent Paul Backus <snarwin gmail.com> writes:
On Tuesday, 9 March 2021 at 14:22:44 UTC, Andrey Zherikov wrote:
 In case of function template this is possible but the original 
 question was about lambdas. There is no way that lambda can 
 change number of parameters during instantiation, am I right?
Yes, you're correct. The issue is that the compiler currently can't tell the difference between a template lambda and a non-lambda function template. This could be changed, but having a language feature that works for lambdas but not for named functions is probably not such a great idea.
Mar 09 2021