Thread overview
Determining if a class has a template function
Oct 11, 2016
Straivers
Oct 12, 2016
Basile B.
Oct 12, 2016
Meta
Oct 12, 2016
Meta
Oct 14, 2016
Marc Schütz
Oct 14, 2016
Meta
October 11, 2016
I have a class T with a templated function foo(string name)(int, int, float) that will be mixed in via template, and I want to determine if that class has mixed it in such that foo(name = "bar"). How could I go about this? Thanks.

eg:

mixin template A(string name, Args...) {
    void foo(string fooName)(Args args)
        if (fooName == name) {}
}

template hasFoo(string name, A) {
    enum hasFoo = ???
}

class B {
    mixin A!("mash", int, int, string);
}


October 12, 2016
On Tuesday, 11 October 2016 at 20:17:19 UTC, Straivers wrote:
> I have a class T with a templated function foo(string name)(int, int, float) that will be mixed in via template, and I want to determine if that class has mixed it in such that foo(name = "bar"). How could I go about this? Thanks.
>
> eg:
>
> mixin template A(string name, Args...) {
>     void foo(string fooName)(Args args)
>         if (fooName == name) {}
> }
>
> template hasFoo(string name, A) {
>     enum hasFoo = ???
> }
>
> class B {
>     mixin A!("mash", int, int, string);
> }

For this particular example the following solution works:

template A(string name, Args...)
{
    void foo(string fooName)(Args args)
        if (fooName == name) {}
}

template hasFoo(string name, T, V...)
{
    enum hasFoo = __traits(hasMember, T, "foo") &&
        is(typeof(T.foo!name) == typeof(A!(name,V).foo!name));
}

class B
{
    mixin A!("mash", int, int, string);
}

unittest
{
    static assert( hasFoo!("mash", B, int, int , string));
    static assert( !hasFoo!("rash", B, int, uint , string));
}


Now I can't say that I's generic enough to validate any members that's injected.
Note well that it wouldn't work with a regular mixin template.

You can also take a look at "std.traits.TemplateOf"
October 12, 2016
On Wednesday, 12 October 2016 at 16:29:22 UTC, Basile B. wrote:
> On Tuesday, 11 October 2016 at 20:17:19 UTC, Straivers wrote:
>> I have a class T with a templated function foo(string name)(int, int, float) that will be mixed in via template, and I want to determine if that class has mixed it in such that foo(name = "bar"). How could I go about this? Thanks.
>>
>> eg:
>>
>> mixin template A(string name, Args...) {
>>     void foo(string fooName)(Args args)
>>         if (fooName == name) {}
>> }
>>
>> template hasFoo(string name, A) {
>>     enum hasFoo = ???
>> }
>>
>> class B {
>>     mixin A!("mash", int, int, string);
>> }
>
> For this particular example the following solution works:
>
> template A(string name, Args...)
> {
>     void foo(string fooName)(Args args)
>         if (fooName == name) {}
> }
>
> template hasFoo(string name, T, V...)
> {
>     enum hasFoo = __traits(hasMember, T, "foo") &&
>         is(typeof(T.foo!name) == typeof(A!(name,V).foo!name));
> }
>
> class B
> {
>     mixin A!("mash", int, int, string);
> }
>
> unittest
> {
>     static assert( hasFoo!("mash", B, int, int , string));
>     static assert( !hasFoo!("rash", B, int, uint , string));
> }
>
>
> Now I can't say that I's generic enough to validate any members that's injected.
> Note well that it wouldn't work with a regular mixin template.
>
> You can also take a look at "std.traits.TemplateOf"

There is also isTemplate (https://dlang.org/spec/traits.html#isTemplate). You can check first that the member exists and then check if it's a template (though this will pick up more than just template functions). There's also a *very* ugly hack you can do:

//A template function's .stringof is of the format <function name>(<template args>)(<function args>)
//so match on the number of brackets to determine whether it's a template function or not
enum isTemplateFunction = __traits(isTemplate, f)
                              && fstr.balancedParens('(', ')')
                              && (fstr.canFind("if")
                                  || fstr.count!(c =>
                                         cast(bool)c.among!('(', ')')) == 4);
October 12, 2016
On Wednesday, 12 October 2016 at 16:57:50 UTC, Meta wrote:
> //A template function's .stringof is of the format <function name>(<template args>)(<function args>)
> //so match on the number of brackets to determine whether it's a template function or not
> enum isTemplateFunction = __traits(isTemplate, f)
>                               && fstr.balancedParens('(', ')')
>                               && (fstr.canFind("if")
>                                   || fstr.count!(c =>
>                                          cast(bool)c.among!('(', ')')) == 4);

Whoops, I forget to say that fstr is defined like this:

enum fstr = f.stringof;
October 14, 2016
On Wednesday, 12 October 2016 at 16:57:50 UTC, Meta wrote:
> There's also a *very* ugly hack you can do:
>
> //A template function's .stringof is of the format <function name>(<template args>)(<function args>)
> //so match on the number of brackets to determine whether it's a template function or not
> enum isTemplateFunction = __traits(isTemplate, f)
>                               && fstr.balancedParens('(', ')')
>                               && (fstr.canFind("if")
>                                   || fstr.count!(c =>
>                                          cast(bool)c.among!('(', ')')) == 4);

This won't work if there are additional parens _inside_ compile/runtime parameters, though, which there is ample opportunity for:

T func(T : U!(int, string), U)(const(T) param = defaultValue!(const(T))());
October 14, 2016
On Friday, 14 October 2016 at 09:15:40 UTC, Marc Schütz wrote:
> On Wednesday, 12 October 2016 at 16:57:50 UTC, Meta wrote:
>> There's also a *very* ugly hack you can do:
>>
>> //A template function's .stringof is of the format <function name>(<template args>)(<function args>)
>> //so match on the number of brackets to determine whether it's a template function or not
>> enum isTemplateFunction = __traits(isTemplate, f)
>>                               && fstr.balancedParens('(', ')')
>>                               && (fstr.canFind("if")
>>                                   || fstr.count!(c =>
>>                                          cast(bool)c.among!('(', ')')) == 4);
>
> This won't work if there are additional parens _inside_ compile/runtime parameters, though, which there is ample opportunity for:
>
> T func(T : U!(int, string), U)(const(T) param = defaultValue!(const(T))());

You're right... And this is why it's such an ugly hack. It can probably be improved upon but I would not recommend trying, although there's no other way I can think of to determine whether a template is a function template.