Thread overview | ||||||
---|---|---|---|---|---|---|
|
January 12, 2011 Generic method that takes in either delegate or function | ||||
---|---|---|---|---|
| ||||
Hi, Is there any way to specify a parameter as "something that can be called with parameter types A, B, C and that returns a value of type D", without caring whether it's a delegate, a function, or an object that overloads opCall? (This might require the use of templates, but I still can't figure it out...) Thank you! |
January 12, 2011 Re: Generic method that takes in either delegate or function | ||||
---|---|---|---|---|
| ||||
Posted in reply to %u | On 01/12/2011 11:21 AM, %u wrote:
> Hi,
>
> Is there any way to specify a parameter as "something that can be called with
> parameter types A, B, C and that returns a value of type D", without caring
> whether it's a delegate, a function, or an object that overloads opCall? (This
> might require the use of templates, but I still can't figure it out...)
>
> Thank you!
See in std.traits:
isSomeFunction
isCallable
ReturnType
ParameterTypeTuple
You can use those in template constraints/static assert conditions.
|
January 12, 2011 Re: Generic method that takes in either delegate or function | ||||
---|---|---|---|---|
| ||||
Posted in reply to %u | On Wednesday 12 January 2011 00:21:54 %u wrote:
> Hi,
>
> Is there any way to specify a parameter as "something that can be called with parameter types A, B, C and that returns a value of type D", without caring whether it's a delegate, a function, or an object that overloads opCall? (This might require the use of templates, but I still can't figure it out...)
>
> Thank you!
Take this example from my proposed std.unittests which is currently under review:
void assertPred(alias pred, string msg = null, string file = __FILE__, size_t
line = __LINE__, T...)
(T args)
if(isCallable!pred &&
is(ReturnType!pred == bool) &&
__traits(compiles, pred(args)) &&
isPrintable!T)
{
immutable result = pred(args);
if(!result)
{
string argsStr;
if(args.length > 0)
{
foreach(value; args)
argsStr ~= format("[%s], ", to!string(value));
argsStr.popBackN(", ".length);
}
else
argsStr = "none";
if(msg.empty)
throw new AssertError(format("assertPred failed: arguments: %s.",
argsStr), file, line);
else
throw new AssertError(format("assertPred failed: arguments: %s: %s",
argsStr, msg), file, line);
}
}
The combination of alias, isCallable, ReturnType, and __traits(compiles) does the trick. isCallable guarantees that pred is callable, but it doesn't care how. ReturnType guarantees that the return type is bool. And __traits(compiles, pred(args)) guarantees that pred can be called with the given arguments.
- Jonathan M Davis
|
January 12, 2011 Re: Generic method that takes in either delegate or function | ||||
---|---|---|---|---|
| ||||
Posted in reply to %u | %u wrote:
> Hi,
>
> Is there any way to specify a parameter as "something that can be called with parameter types A, B, C and that returns a value of type D", without caring whether it's a delegate, a function, or an object that overloads opCall? (This might require the use of templates, but I still can't figure it out...)
>
> Thank you!
Yes, look at std.traits. isCallable determines if a type can be called, ReturnType gives you the return type and ParameterTypeTuple obtaines a tuple of the parameters. In this example I used all three, isCallable is implied by the latter two so that is actually redundant:
import std.traits;
import std.stdio;
import std.typetuple;
int square(int a)
{
return a*a;
}
struct Squarer
{
int opCall(int a)
{
return a * a;
}
}
void foo(T)(T fun, int num)
if (isCallable!(T)
&& is(ReturnType!fun == int)
&& is(ParameterTypeTuple!(T) == TypeTuple!(int)))
{
writeln("square of ", num, ":", fun(num));
}
void main()
{
foo(&square, 2);
Squarer functor;
foo(functor, 2);
foo((int a) { return a * a; }, 2);
}
Another (efficient) way to do this is with alias template parameters, this determines not the type of the object / function / delegate, but the actual symbol directly. However, it must be able to access that symbol, see this example:
void foo2(alias fun)(int num)
if (isCallable!(fun)
&& is(ReturnType!(fun) == int)
&& is(ParameterTypeTuple!(fun) == TypeTuple!(int)))
{
writeln("square of ", num, ":", fun(num));
}
void main()
{
Squarer functor;
foo2!square(2);
//foo2!functor(2); error: cannot access frame of function D main
foo2!((int a) { return a * a; })(2);
}
foo2 is trying to call opCall of the functor object, but it is a local variable of the main function so it cannot be called this way.
|
Copyright © 1999-2021 by the D Language Foundation