Partially instantiating templates?

Simen kjaeraas simen.kjaras at gmail.com
Mon Jan 31 06:50:41 PST 2011


Magnus Lie Hetland <magnus at hetland.org> wrote:

>> Might I also ask why you use an out parameter instead of a tuple return?
>
> Well... I had a tuple return at first, but one of the advantages of  
> returning multiple values that I'm accustomed to is the ability to  
> assign to multiple variables, such as
>
>   arg, val = minArg(...)
>
> (Yeah, I'm a Python guy... ;)
>
> As far as I can see, you can't do that here? Using result[0] and  
> result[1] or the like, or assigning separately to two variables just  
> seemed more cumbersome. Then again, I could use a tuple with named  
> members, I guess. In your opinion, what would be the prettiest (in D  
> terms) way of doing this?

You might want to try more from dranges - the reftuple:

_(arg,val) = minArg(...);

It resides in dranges.reftuple, and still has some warts, but it
usually works.

This is also a possible implementation (coded in about 5 minutes, gives
no nice error messages, but it seems to work :p ):


import std.typetuple;
import std.typecons;

template TypeOf( alias T ) {
     alias typeof( T ) TypeOf;
}

@property void _( T... )( Tuple!( staticMap!(TypeOf, T) ) args ) {
     foreach ( i, e; T ) {
         e = args[i];
     }
}

void main( ) {
     int a, b;
     _!(a,b) = tuple(b,a+b); // fibonacci
}


> I see. I actually don't mind writing nested templates myself -- but for  
> some reason I couldn't get them to work properly. (D kept complaining  
> about declarations vs instances, and the like; I guess I'll have a look  
> at how dranges does it.)

Yeah. D has the nice Eponymous Template Trick, but it sadly only works
for one level. :(


> By the way, if you have suggestions for other more "D-like" ways of  
> encapsulating this functionality (basically a linear scan for an element  
> that yields a max/min value for a given expression), I'd be interested  
> to hear that too. The best way to solve a problem is often to rephrase  
> it :)

So you have to test for every single element of the range?

If so, I think this works:


module foo;

import std.typecons;
import std.functional;
import std.array;

template optArg( alias pred ) {
     template optArg( alias fn ) {
         auto optArg( Range )( Range r ) {
             alias binaryFun!pred predicate;
             alias unaryFun!fn func;

             auto result = tuple( r.front, func( r.front ) );
             foreach ( e; r ) {
                 auto tmp = func( e );
                 if ( predicate( e, result[1] ) ) {
                     result = tuple( e, tmp );
                 }
             }
             return result;
         }
     }
}

void main( ) {
     alias optArg!"a<b" minArg;
     alias minArg!"a" foo;
     assert( foo( [5,2,1,3] ) == tuple(1,1) );
}



-- 
Simen


More information about the Digitalmars-d-learn mailing list