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. I predict you guys will soon need (and I am happy you are approaching this way-point) a means to get from a symbol to its parent, that is __traits(parent, symbol).

So there are two ways to solve the problem:

1. Add a version of __traits(getOverloads) that would not require a parent as you suggested.
2. Add __traits(parent), so one could do:

void foo();
void foo(int);

alias __traits(getOverloads, __traits(parent, foo), "foo") fooOverloads;

I prefer the second or both, because the parent trait is needed in other scenarios.


Anyway, I've been able to make the following work for selecting overloads
of member functions:


import std.traits, std.stdio;

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

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

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

void main()
{
     S s;
     s.test();
}



template selectOverload(T, string fun, Params...)
{
     alias selectOverloadImpl!(Params.length, Params,
         __traits(getOverloads, T, 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 .. $]);
}

Reply via email to