On 01/05/2011 12:24 PM, Lars T. Kyllingstad wrote:
On Wed, 05 Jan 2011 12:07:50 +0200, Max Samukha wrote:

On 01/05/2011 11:21 AM, Lars T. Kyllingstad wrote:
On Tue, 04 Jan 2011 17:06:45 -0600, Andrei Alexandrescu wrote:

On 1/4/11 4:49 PM, %u wrote:
There's still the risk of keeping multiple hashes. Consider:

ulong fun(ulong n) { ... }
alias memoize!fun mfun;

mfun(5); // creates hash ulong[int]
mfun(5u); // creates hash ulong[uint] mfun('5'); // creates hash
ulong[char]


Ohhh I see... so you're basically looking for a compile-time version
of overload resolution, right? Because things seem to be getting
complicated very quickly.

It's not that complicated; we'll be able to achieve it somehow.
Overloads are compile-time entities so they should be easily
inspectable.

Since this is likely to be useful in other cases as well, maybe it
would be better to make a general template that selects an overload?
So you'd use it like this:

    alias memoize!(selectOverload!(sqrt, double)) msqrt;

A first step towards this would be to make __traits(getOverloads) work
with module-level functions.  Currently it only works for member
functions.  Also it would probably be better if it accepted a function
alias instead of a string containing the function name.

__traits(getOverloads) does work with module level functions if you pass
a module alias to it.

Cool!  I didn't know that.  Here's an updated version, where
selectOverload works with both module-level and member functions:


module test;
import std.traits, std.stdio;

void foo(int i, double d) { writeln("Overload 1"); }
void foo(double d, int i) { writeln("Overload 2"); }

void main()
{
     alias selectOverload!(test, "foo", int, double) bar;
     bar(1, 3.0);    // Prints "Overload 1"

     alias selectOverload!(test, "foo", double, int) baz;
     baz(4.0, 2);    // Prints "Overload 2"
}



template selectOverload(alias parent, string fun, Params...)
{
     alias selectOverloadImpl!(Params.length, Params,
         __traits(getOverloads, parent, fun)) selectOverload;
}


template selectOverloadImpl(size_t lenP, A...)
{
     static assert (A.length>  lenP, "No overload matches");
     static if (equalTuples!(lenP,
         A[0 .. lenP],
         ParameterTypeTuple!(A[lenP])))
     {
         alias A[lenP] selectOverloadImpl;
     }
     else
     {
         alias selectOverloadImpl!(lenP, A[0 .. lenP], A[lenP+1 .. $])
             selectOverloadImpl;
     }
}


template equalTuples(size_t len, T...)
{
     static if (len == 0&&  T.length == 0)
         enum equalTuples = true;
     else static if (T.length != len*2)
         enum equalTuples = false;
     else static if (!is (T[0] == T[len]))
         enum equalTuples = false;
     else
         enum equalTuples =
             equalTuples!(len-1, T[1 .. len], T[len+1 .. $]);
}

Nice! Though I think that overloads should be selected not by type equality but by regular overload resolution rules. That is the template should take not parameter but argument types.

Reply via email to