Pass function (not alias) to template and/or delegate-ize a template argument
ag0aep6g
anonymous at example.com
Mon Jun 11 13:41:09 UTC 2018
On 06/11/2018 08:46 AM, cc wrote:
> struct MYUDA {}
> class Foo {
> @(MYUDA) int bar(int x) { return x*2; }
> }
> auto foo = new Foo();
[...]
> I did figure out I can do it with mixins like so:
>
> void MCALL(string func, V...)(V args) {
> mixin(`assert(hasUDA!(`~func~`, MYUDA));`); // Ok
> mixin(`assert(`~func~`(args) == 16);`); // Ok
> }
> MCALL!"foo.bar"(8);
>
> Which works. Is this the "best" way to do this?
That only works when foo is visible to MCALL. That's a serious limitation.
> Or is there another pattern that looks cleaner?
I can't think of a really nice solution where you just pass `foo.bar` or
`&foo.bar`. The problem is that an alias of `foo.bar` is really an alias
of `Foo.bar`, i.e. there is no connection to the object `foo`. And
`&foo.bar` is just a generic delegate. There is no (compile-time) type
information that links it to the type `Foo`.
The best I could come up with is passing the method's name separately
from the object:
----
void main()
{
auto foo = new Foo();
foo.nCall!"bar"(9);
}
void nCall(string methodName, O, V...)(O obj, V args)
/* 'n' is for "name" */
{
import std.traits: hasUDA;
auto methodDelegate = mixin("&obj." ~ methodName);
mixin("alias methodAlias = obj." ~ methodName ~ ";");
assert(hasUDA!(methodAlias, MYUDA)); // Ok
assert(methodDelegate(args) == 18); // Ok
}
struct MYUDA {}
class Foo
{
@(MYUDA) int bar(int x) { return x*2; }
}
----
If it's feasible to hard-code a list of all possible object types into
the "call" function, then you can pass `&foo.bar` and find the correct
object type by trying them all:
----
void main()
{
auto foo = new Foo();
bCall(&foo.bar, 9);
}
void bCall(D, V...)(D methodDelegate, V args)
/* 'b' is for "bloat" */
{
import std.traits: hasUDA;
import std.meta: AliasSeq;
assert(methodDelegate(args) == 18); // Ok
auto obj = cast(Object) methodDelegate.ptr;
if (obj is null) return; /* Delegate is not of a method. */
static foreach (O; AliasSeq!(Foo, /* Bar, Baz, etc */))
{
static foreach (mName; __traits(allMembers, O))
{{
alias m = AliasSeq!(__traits(getMember, O, mName))[0];
static if (is(typeof(&m)))
{
if (typeid(O) == typeid(obj) &&
&m is cast(void*) methodDelegate.funcptr)
{
assert(hasUDA!(m, MYUDA)); // Ok
}
}
}}
}
}
struct MYUDA {}
class Foo
{
@(MYUDA) int bar(int x) { return x*2; }
}
----
But that's probably not feasible.
More information about the Digitalmars-d-learn
mailing list