www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Template argument deduction (not the implicit kind)

reply Andy Friesen <andy ikagames.com> writes:
The current ML-ish pattern-matching style of templates is great, but 
currently has a few inconvenient limitations.

For instance, we can specialize a template for all arrays by doing

     template Templ(T : T[]) { ... }

Which specializes for all arrays.  The pattern is matched against the 
actual type supplied; this particular pattern matches all arrays, but 
only arrays.  The template argument T recieves the type of an element of 
this array type.

There are one relatively big thing we can't do, though:

We can't match more than one type from a single supplied type, or match 
part of a type without capturing it into an argument which would have to 
be explicitly specified anyway.

This makes it impossible, for instance, to specialize on associative 
arrays.  We can do

     template Templ(T : T[T]) { ... }

But this will only match an AA whose key and value types are identical. 
  The solution is somewhere along the lines of

     template Templ(Key, Value : Value[Key]) { ... }

There's a pretty big problem, though: we have to supply the key type 
along with the associative array type when we use it.  This is clumsier 
than just passing Key and Value explicitly, and so is effectively 
useless: we have no way to detect whether a type is an AA or not.


I don't know how much of a strain it would place on the template 
specialization system, but it would be great if these patterns could 
match on more than one template argument.

All that remains is to keep it clear just how many arguments are to be 
supplied when instantiating the template:

    // the pattern applies to a group, and not just one argument
    template Templ( (Key, Value) : Value[Key])

A second, perhaps simpler idea that comes to mind is a way to express a 
constraint without affecting the value that the template argument 
recieves.  For instance, we could do

     // null matches any type but does nothing with it; AA recieves the 
exact type passed
     template Templ(AA : null[null])

     // matches all AAs; the key type is captured
     template Templ(KeyType : null[KeyType])

     // capture the return type of a delegate that recieves exactly one 
argument of any type
     template Templ(ReturnType : ReturnType delegate(null))

     template Templ(T : null!(T)) // dare I hope?  Catch any template 
instantiation that recieved exactly one argument

  -- andy
Jul 31 2004
parent reply Sean Kelly <sean f4.ca> writes:
Andy Friesen wrote:
 
 We can't match more than one type from a single supplied type, or match 
 part of a type without capturing it into an argument which would have to 
 be explicitly specified anyway.
 
 This makes it impossible, for instance, to specialize on associative 
 arrays.  We can do
 
     template Templ(T : T[T]) { ... }
 
 But this will only match an AA whose key and value types are identical. 
  The solution is somewhere along the lines of
 
     template Templ(Key, Value : Value[Key]) { ... }
I'd been meaning to try this out. If it's not possible then it definately should be. And by the syntax you describe. I'd also like to have something like template template parameteres, though the syntax for these is a bit less clear. Perhaps this? template Templ( Key!(Value) ) {}
 All that remains is to keep it clear just how many arguments are to be 
 supplied when instantiating the template:
 
    // the pattern applies to a group, and not just one argument
    template Templ( (Key, Value) : Value[Key])
I'm not sure about this... how many arguments are supplied, 1 or 2?
     // null matches any type but does nothing with it; AA recieves the 
 exact type passed
     template Templ(AA : null[null])
 
     // matches all AAs; the key type is captured
     template Templ(KeyType : null[KeyType])
I like what you're getting at but Walter's probably the only one who can answer which syntax works best. Any way you cut it though, we'll need to be able to do this type of stuff. Sean
Jul 31 2004
parent Andy Friesen <andy ikagames.com> writes:
Sean Kelly wrote:

 All that remains is to keep it clear just how many arguments are to be 
 supplied when instantiating the template:

    // the pattern applies to a group, and not just one argument
    template Templ( (Key, Value) : Value[Key])
I'm not sure about this... how many arguments are supplied, 1 or 2?
One. The rule would be that every group recieves exactly one argument from the caller. For instance, something like this would demand four input arguments and produce six type arguments for use by the implementation: template ScaryPermutation( (LeftKey, LeftValue) : LeftKey[LeftValue], (RightKey, RightValue) : RightKey[RightValue], alias Comparer, ResultType : ResultType[] ) { ... } Every group must have a specialization, and every element of a group must match at least one part of that specialization.
     // null matches any type but does nothing with it; AA recieves the 
 exact type passed
     template Templ(AA : null[null])

     // matches all AAs; the key type is captured
     template Templ(KeyType : null[KeyType])
I like what you're getting at but Walter's probably the only one who can answer which syntax works best. Any way you cut it though, we'll need to be able to do this type of stuff.
Right. It's just a matter of what's easier to implement and use. :) -- andy
Jul 31 2004