Thread overview
Double face templates
Sep 29, 2008
bearophile
Sep 29, 2008
BCS
Sep 30, 2008
bearophile
Oct 01, 2008
Don
September 29, 2008
I have created several templates, like one very simple named ArrayType1 that given the type of an array becomes an alias of the type of its items (there are other more complex templates too).

They can be used as:
ArrayType1!(TypeArray)
or:
ArrayType1!(typeof(somearray))

But to reduce code clutter if possible I'd like to create a template that works in both cases:
ArrayType1!(TypeArray)
ArrayType1!(somearray)

I know template "arguments" can be an alias too, so I may define a pair like this:
template ArrayType1!(T) {...}
template ArrayType1!(alias x) { ... }
but when I define both templates I always enter a swamp, with so many (sometimes strange) bugs that so far I have always thrown away the template version with alias and I have kept only the more normal template defined on a type.

Is what I am trying to do wrong/ unsafe/ philosophically bad?
If my purpose isn't bad, then can you suggest how to implement it much more reliably?

Thank you,
bearophile
September 29, 2008
Reply to bearophile,

> I have created several templates, like one very simple named
> ArrayType1 that given the type of an array becomes an alias of the
> type of its items (there are other more complex templates too).
> 
> They can be used as:
> ArrayType1!(TypeArray)
> or:
> ArrayType1!(typeof(somearray))
> But to reduce code clutter if possible I'd like to create a template
> that works in both cases:
> ArrayType1!(TypeArray)
> ArrayType1!(somearray)
> I know template "arguments" can be an alias too, so I may define a
> pair like this:
> 
> template ArrayType1!(T) {...}
> 
> template ArrayType1!(alias x) { ... }
> 
> but when I define both templates I always enter a swamp, with so many
> (sometimes strange) bugs that so far I have always thrown away the
> template version with alias and I have kept only the more normal
> template defined on a type.
> 
> Is what I am trying to do wrong/ unsafe/ philosophically bad? If my
> purpose isn't bad, then can you suggest how to implement it much more
> reliably?
> 
> Thank you,
> bearophile

you might be able to use a form like this

template T(alias a)
{
   static if(is(a))
   {
      // stuff
   }
   else
      alias T!(typeof(a)) T;
   // or 'mixin T!(typeof(a));'
}


September 30, 2008
BCS:
> you might be able to use a form like this
> template T(alias a)
> {
>     static if(is(a))
>     {
>        // stuff
>     }
>     else
>        alias T!(typeof(a)) T;
>     // or 'mixin T!(typeof(a));'
> }

I think it doesn't work:

import std.stdio;

template ArrayType1(T: T[]) {
    alias T ArrayType1;
}

template Foo(alias x) {
    static if(is(x))
       alias ArrayType1!(x) Foo;
    else
       alias ArrayType1!(typeof(x)) Foo;
}

void main() {
    alias string[] Ts;
    Ts s = ["aaaa", "bb"];
    writefln(typeid( Foo!(s) ));
    writefln(typeid( Foo!(Ts) ));
}

But it doesn't matter much, I'll keep using just the version of the templates that take a type...

Bye and thank you,
bearophile
October 01, 2008
bearophile wrote:
> BCS:
>> you might be able to use a form like this
>> template T(alias a)
>> {
>>     static if(is(a))
>>     {
>>        // stuff
>>     }
>>     else
>>        alias T!(typeof(a)) T;
>>     // or 'mixin T!(typeof(a));'
>> }
> 
> I think it doesn't work:
> 
> import std.stdio;
> 
> template ArrayType1(T: T[]) {
>     alias T ArrayType1;
> }
> 
> template Foo(alias x) {
>     static if(is(x))
>        alias ArrayType1!(x) Foo;
>     else
>        alias ArrayType1!(typeof(x)) Foo;
> }
> 
> void main() {
>     alias string[] Ts;
>     Ts s = ["aaaa", "bb"];
>     writefln(typeid( Foo!(s) ));
>     writefln(typeid( Foo!(Ts) ));
> }
> 
> But it doesn't matter much, I'll keep using just the version of the templates that take a type...
> 
> Bye and thank you,
> bearophile

It works if you change alias string[] Ts; into a typedef.

The reason is that aliases get resolved at a very early stage. There's no difference at all between string[] and Ts, and string is itself an alias, not a typedef. So Ts gets turned into char[][] before template lookup happens.

Built-in types can't be alias template parameters, unfortunately. Which kills the "double face template" idea.