www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template detection

reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
Hello,

Given:

class SomeClass {

     public {
         void someSimpleMethod() {}

         template setOfTemplatedMethods(Type) {
             void templatedMethodOne() {}
             void templatedMethodTwo() {}
         }
     }
}

Is there a way to detect at compile time if a member of 
class/struct is a template? (in the example above, if 
setOfTemplatedMethods is a template).
Sep 13 2015
next sibling parent reply Enamex <enamex+d outlook.com> writes:
On Sunday, 13 September 2015 at 08:26:55 UTC, Alexandru Ermicioi 
wrote:
 Hello,

 Given:

 class SomeClass {

     public {
         void someSimpleMethod() {}

         template setOfTemplatedMethods(Type) {
             void templatedMethodOne() {}
             void templatedMethodTwo() {}
         }
     }
 }

 Is there a way to detect at compile time if a member of 
 class/struct is a template? (in the example above, if 
 setOfTemplatedMethods is a template).
There's this: http://stackoverflow.com/questions/5483381/test-if-an-alias-is-a-template-in-d-2-0 and it should work with 'member templates' OK.
Sep 13 2015
parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Sunday, 13 September 2015 at 09:29:13 UTC, Enamex wrote:
 On Sunday, 13 September 2015 at 08:26:55 UTC, Alexandru 
 Ermicioi wrote:
 Hello,

 Given:

 class SomeClass {

     public {
         void someSimpleMethod() {}

         template setOfTemplatedMethods(Type) {
             void templatedMethodOne() {}
             void templatedMethodTwo() {}
         }
     }
 }

 Is there a way to detect at compile time if a member of 
 class/struct is a template? (in the example above, if 
 setOfTemplatedMethods is a template).
There's this: http://stackoverflow.com/questions/5483381/test-if-an-alias-is-a-template-in-d-2-0 and it should work with 'member templates' OK.
Thx for the provided link. I've tried to implement version from the stackoverflow answer, and run against tests provided in another answer to the question in link, and failed. With dmd version 2.067.1 this implementation fails at static assert(! isTemplate!(FooS!int.func!float) ); static assert(! isTemplate!(FooS!int.bar) ); for .func it requires "this" (an value of type FooS, or isTemplate fails to instantiate). and for .bar it just fails (isTemplate detects it as a template). I've found another way to detect if a symbol is a template. The idea is that for a not instantiated template you can get with allMembers trait the list of members in template, but you can't access them using getMembers trait since the template is not instantiated yet. So if there is a symbol that has members which cannot be accessed using getMember (generates an error) then this is a template! template allMembers(alias Type) { alias allMembers = TypeTuple!(__traits(allMembers, Type)); } template anyAccessible(alias Container, T...) { static if (T.length > 1) { enum bool anyAccessible = anyAccessible!(Container, T[0 .. $ / 2]) || anyAccessible!(Container, T[$ / 2 .. $]); } else static if (T.length == 1) { enum bool anyAccessible = __traits(compiles, getMember!(Container, T[0])); } else { enum bool anyAccessible = false; } } template isTemplate(alias T) { static if ( // check if symbol has members __traits(compiles, TypeTuple!(__traits(allMembers, T))) && !T.stringof.startsWith("module ", "package ") ) { enum bool isTemplate = (allMembers!(T).length > 0) && !anyAccessible!(T, allMembers!T); } else { enum bool isTemplate = false; } } It passes almost all tests except for: static assert(! isTemplate!((int x){return x;}) ); static assert(! isTemplate!(std) ); static assert(! isTemplate!(core) ); I don't know how but in this cases, compiler attempts to parse true branch of static if, even if the expression in static if is false. For lamda function allMembers trait fails to get the members and an error is created by compiler. For std, and core packages isTemplate evaluates to true even if expression from static if is false. Is such behavior of static if correct (tested also with ldc compiler, same results)? If there are other test cases, would be glad if they are posted here (to improve the accuracy of template detection). Tests are: struct FooS(T) { struct Inner {} struct Inner2(string U="!(") {} int func(U)() { return 0; } int bar; } FooS!int foo; class FooC { int x; } union FooU { int x;} enum FooE { x } interface FooI { int x(); } template FooT(T) { struct Inner {} struct Inner2(string U="!(") {} int func(U)() { return 0; } int bar; } static assert(! isTemplate!0 ); static assert(! isTemplate!"0" ); static assert(! isTemplate!0.0f ); static assert(! isTemplate!'0' ); static assert(! isTemplate!'!' ); static assert(! isTemplate!"module std.stdio" ); static assert(! isTemplate!null ); static assert(! isTemplate!true ); static assert(! isTemplate!__FILE__ ); static assert(! isTemplate!__LINE__ ); static assert(! isTemplate!([]) ); static assert( isTemplate!FooS ); static assert(! isTemplate!(FooS!int) ); static assert( isTemplate!(FooS!int.func) ); static assert(! isTemplate!(FooS!int.func!float) ); static assert(! isTemplate!(FooS!int.bar) ); static assert(! isTemplate!(FooS!int.Inner) ); static assert( isTemplate!(FooS!int.Inner2) ); static assert(! isTemplate!(FooS!int.Inner2!"?") ); static assert( isTemplate!FooT ); static assert(! isTemplate!(FooT!int) ); static assert( isTemplate!(FooT!int.func) ); static assert(! isTemplate!(FooT!int.func!float) ); static assert(! isTemplate!(FooT!int.bar) ); static assert(! isTemplate!(FooT!int.Inner) ); static assert( isTemplate!(FooT!int.Inner2) ); static assert(! isTemplate!(FooT!int.Inner2!"?") ); static assert(! isTemplate!foo ); static assert( isTemplate!(foo.func) ); static assert( isTemplate!isTemplate ); static assert(! isTemplate!(isTemplate!isTemplate) ); static assert(! isTemplate!FooC ); static assert(! isTemplate!FooU ); static assert(! isTemplate!FooE ); static assert(! isTemplate!FooI ); static assert(! isTemplate!((int x){return x;}) ); static assert( isTemplate!(std.stdio.writefln) ); static assert(! isTemplate!(std.stdio) ); static assert(! isTemplate!std ); static assert(! isTemplate!(core) );
Sep 22 2015
prev sibling parent reply Meta <jared771 gmail.com> writes:
On Sunday, 13 September 2015 at 08:26:55 UTC, Alexandru Ermicioi 
wrote:
 Hello,

 Given:

 class SomeClass {

     public {
         void someSimpleMethod() {}

         template setOfTemplatedMethods(Type) {
             void templatedMethodOne() {}
             void templatedMethodTwo() {}
         }
     }
 }

 Is there a way to detect at compile time if a member of 
 class/struct is a template? (in the example above, if 
 setOfTemplatedMethods is a template).
You can use __traits(isTemplate, <symbol>).
Sep 22 2015
parent reply Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Tuesday, 22 September 2015 at 15:37:32 UTC, Meta wrote:
 On Sunday, 13 September 2015 at 08:26:55 UTC, Alexandru 
 Ermicioi wrote:
 Hello,

 Given:

 class SomeClass {

     public {
         void someSimpleMethod() {}

         template setOfTemplatedMethods(Type) {
             void templatedMethodOne() {}
             void templatedMethodTwo() {}
         }
     }
 }

 Is there a way to detect at compile time if a member of 
 class/struct is a template? (in the example above, if 
 setOfTemplatedMethods is a template).
You can use __traits(isTemplate, <symbol>).
Thx. Didn't know that there is such trait available. On page http://dlang.org/traits.html it's not present.
Sep 22 2015
parent Meta <jared771 gmail.com> writes:
On Tuesday, 22 September 2015 at 16:11:59 UTC, Alexandru Ermicioi 
wrote:
 Thx. Didn't know that there is such trait available.

 On page http://dlang.org/traits.html it's not present.
Yeah, it's undocumented for some reason. Somebody must've forgot to make a corresponding doc pull request I suppose.
Sep 22 2015