www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Template grammar issues

I have a feeling that this is actually working as intended, but the behavior I'm
interested in is so close to the grammar in the spec that I figured I'd
crosspost this to the bugs forum anyway.

Recently, I've been looking for a way to specialize templates on a list of
types.  So far, I've found one form that works:

# template isInt32( T )
# {
#     static if( is( T == int ) || is( T == uint ) ) const bit isInt32 = true;
#     else const bit isInt32 = false;
# }
# template fn1( T, bit test : true = isInt32!(T) )
# {
#     void fn1()
#     {
#         static assert( isInt32!(T) );
#     }
# }
# class fn2( T, bit test : true = isInt32!(T) )
# {
#     static assert( isInt32!(T) );
#     static void opCall() {}
# }
# void main()
# {
#     fn1!(int)();
#     fn2!(int)();
# }

Note that in the above example, I had to put the static assert inside fn1()
because putting it in template scope broke the implicit template property
feature (calling fn1 would then require me to use fn1!(int).fn1()).  While this
works, using it is a tad clunky, and I don't like having to use a static assert
just to guarantee that the user isn't trying to fool my system by setting the
second template parameter manually.  Also, it would be *very* nice if static
assertions were ignored for the sake of implicit property checking.  Static
assertions don't expose any referencable symbols so this seems quite reasonable
in my opinion.  Without this change, the first form would not work if it
contained merely an alias or something similarly without its own scope to put
the assertion in.

Here is an alternate form of specialization that seems like it should work given
a sufficiently loose interpretation of the grammar, but it does not:

# template selectInt32( T, U = int )
# {
#     static if( is( T == int ) || is( T == uint ) ) alias T checkInt32;
#     else alias U checkInt32;
# }
# template fn( T : selectInt32!(T) )
# {
#     void fn() {}
# }
# void main()
# {
#     fn!(int)();
# }

This fails with the following messages:

sample2.d(1): identifier 'T' is not defined
sample2.d(1): T is used as a type
sample2.d(7): selectInt32!(T) is used as a type

It would be nice if 'Type' in the template spec were re-interpreted to include
templates that expand into types.  Since my first example works (and therefore
any issues with recursive template instantiation already exist) I see no reason
for this example not to work also.  If not, the errors above should be improved
as the first two make no sense given the code provided.  For what it's worth,
I've tried passing typeof(T) to selectInt32 with the same result.

Finally, the ideal solution would be to extend the syntax to support type lists
naturally.  The most obvious syntax would be something like this:

template Eval( T : [int,uint] ) {}

Which could extend to work with static is also:

static if( is( int : [int,uint] ) ) {}

Being able to use the existing static array syntax for typelists would be a
great boon, especially if there were a way to reference them:

static type[] typeList = [int,uint];

template Eval( T ) {}
template Get( T, int pos ) { alias T[pos] Get; }

Get!(typeList, 0);

I suppose it may make sense to change the template syntax a bit to support
passing a typelist:

template Get( T[], int pos ) {}

though this may turn out to be limiting--I haven't given it enough thought.

Jul 29 2005