get parameters of a function

Stanislav Blinov via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sat Apr 29 01:15:06 PDT 2017


On Saturday, 29 April 2017 at 06:18:34 UTC, Alex wrote:

> The problem is another one: say I have something like this:
>
> import std.traits;
>
> struct A(alias T) if(isCallable!T)
> {	
> 	auto opCall(U...)(U args) if(is(Parameters!T == U)) 
> //if(__traits(compiles, T(args)))
> 	{
> 		return T(args);
> 	}
> }
>
> void main()
> {
> 	S s;
> 	A!s c;
> 	assert(c(4) == 42);
> }
>
> struct S
> {
> 	auto opCall(){ return 42; }
> 	auto opCall(int i){return 42; }
> }
>
> This doesn't work because of Parameters trait and the both 
> opCalls defined.
> However, I see the point...
> If I take the compiles-trait, it works as expected:
> In this case the constrained is fulfilled, and with the second 
> opCall commented out - it isn't.
>
> Thanks :)

Ah, that calls for something like a isCallableWith template. Pay 
extra care to how you pass parameters in that variadic opCall 
template though. Doing it like in the code above will pass 
everything by value, even though the original S.opCall might've 
expected a reference. To avoid that, auto ref + 
std.functional.forward can be used.
The following code illustrates the difference.

import std.traits;
import std.functional : forward;

/**
   Evaluates true if `func` is callable with arguments `args`.
   Can only be used as a function template constraint.
*/
enum isCallableWith(alias func, args...) = 
is(typeof(func(forward!args)));

// Your original A
struct A(alias func) if (isCallable!func)
{
     auto opCall(Args...)(Args args) if (__traits(compiles, 
func(args)))
     {
         // all arguments are copied, any "ref/out" semantics are 
lost
         return func(args);
     }
}

// Modified to forward arguments
struct B(alias func) if (isCallable!func)
{
     // auto ref: preserve lvalues
     auto opCall(Args...)(auto ref Args args) if 
(isCallableWith!(func, args))
     {
         // forward: preserve lvalues
         return func(forward!args);
     }
}

struct S
{
     auto opCall() { return 42; }
     auto opCall(int i) { return 42; }
     // Note: parameter passed by reference!
     auto opCall(out float f) { f = 42.0f; }
}

void main()
{
     S s;

     {
         A!s c;
         int i = 4;
         static assert(is(typeof(c(i))));
         static assert(is(typeof(c(4))));
         static assert(is(typeof(c())));

         assert(c(i) == 42);
         assert(c(4) == 42);
         assert(c() == 42);
         // Should pass but doesn't.
         //static assert(!is(typeof(c(3.5f))));
         float f;
         static assert(is(typeof(c(f))));
         c(f);
         // Will assert:
         assert(f == 42.0f);
     }

     {
         B!s c;
         int i = 4;
         static assert(is(typeof(c(i))));
         static assert(is(typeof(c(4))));
         static assert(is(typeof(c())));

         assert(c(i) == 42);
         assert(c(4) == 42);
         assert(c() == 42);
         // Passes
         static assert(!is(typeof(c(3.5f))));
         float f;
         static assert(is(typeof(c(f))));
         c(f);
         // Won't assert
         assert(f == 42.0f);
     }
}


More information about the Digitalmars-d-learn mailing list