www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Determining if a class has a template function

reply Straivers <straivers98 gmail.com> writes:
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);
}
Oct 11 2016
parent reply Basile B. <b2.temp gmx.com> writes:
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"
Oct 12 2016
parent reply Meta <jared771 gmail.com> writes:
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);
Oct 12 2016
next sibling parent Meta <jared771 gmail.com> writes:
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;
Oct 12 2016
prev sibling parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
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))());
Oct 14 2016
parent Meta <jared771 gmail.com> writes:
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.
Oct 14 2016