Compile time variadic functions

Oskar Linde oskar.lindeREM at OVEgmail.com
Wed Mar 15 01:25:26 PST 2006


Don Clugston skrev:
> Oskar Linde wrote:
>> struct myFuncImplDummy { mixin decl_vararg_func!(myFuncImpl); }
>> alias myFuncImplDummy.func myFunc;
>>
>> Is there any better way to do the decl_vararg_func and dummy struct 
>> thing? An identifier name template parameter type would be awesome* (I 
>> would have other uses for that as well).
> 
> // Just change the 'func' to decl_vararg_func to take advantage
> // of implicit template name promotion.
> template decl_vararg_func(alias realFunc) {
>   template decl_vararg_func(A = Empty, B = Empty, C = Empty, D = Empty, 
> E = Empty, F = Empty, G = Empty /*, ...*/) {
>     static void decl_vararg_func(A a = A.init, B b = B.init, C c = 
> C.init, D d = D.init, E e = E.init, F f = F.init, G g = G.init /*,...*/) {
>       realFunc(Tuple(a,b,c,d,e,f,g /*,...*/));
>     }
>   }
> }
> 
> // and there's no need for a mixin.
> alias decl_vararg_func!(funcImpl) myFunc;

Of course. How silly of me :) And it easy to add should support for 
optional return values too:

template decl_vararg_func(alias realFunc) {
   template decl_vararg_func(A = Empty, B = Empty, C = Empty, D = Empty, 
E = Empty, F = Empty, G = Empty /*, ...*/) {
 
typeof(realFunc(Tuple(A.init,B.init,C.init,D.init,E.init,F.init,G.init 
/*,...*/))) decl_vararg_func(A a = A.init, B b = B.init, C c = C.init, D 
d = D.init, E e = E.init, F f = F.init, G g = G.init /*,...*/) {
       return realFunc(Tuple(a,b,c,d,e,f,g /*,...*/));
     }
   }
}

> 
> 
> Which means the best effort so far is:
> 
> 
>  > import variadic;
>  >
>  > template myFuncImpl(T) {
>  >   void myFuncImpl(T) {
>  >     static if (is (T == Empty)) {
>  >       writefln("Done");
>  >     } else {
>  >       writefln("Got argument %s of type %s",args.head,
>  >                typeid(typeof(args.head)));
>  >       .myFuncImpl(T.tail); // tail-recurse
>  >     }
>  >   }
>  > }
>  >
>  > alias decl_vararg_func!(myFuncImpl) myFunc;
>  >
>  > void main() {
>  >   myFunc(1.0,2,3L);
>  >   myFunc();
>  > }

It doesn't get any better than this (unless we get a short hand notation 
for function templates).

Static array arguments are still a problem though. Static arrays need 
some special handling:
- They are are the only type I know of where !is(T == typeof(T.init))
- They have schizophrenic value/reference semantics. (Behaves as a value 
type (declaring space) on declaration, but is a reference type otherwise)
- There is no way (that I know of) to define template specializations 
generically for static arrays. (Only for static arrays of a defined 
number of elements)

The first can be worked around:

Change the default argument value from T.init to Init!(T):

template Init(T) {
   const T Init = void;
}

The second is harder:

struct Container(T) { T element; }
...
Container!(typeof(x)) container;
container.element = x; // Works for all types except static arrays.

Meaning I have to convert static arrays into dynamic arrays:

template Declare(T) { T Declare; }
...
// Convert static arrays types into dynamic array types
template Dynify(T) {
   static if (is (typeof(Declare!(T)[0]) E)) // Indexable
     static if (is (T : E[])) // Implicitly convertible to dynamic array
       alias E[] Dynify;
     else
       alias T Dynify;
   else
     alias T Dynify;
}

With those changes:

myFunc("hello",5,2.3);

works. (Attaching the code again)

/Oskar
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: variadic.d
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20060315/7f6dc8ed/attachment.ksh>


More information about the Digitalmars-d mailing list