Calling all D template gurus: exposing the overload/template matching system via std.traits
John Colvin via Digitalmars-d
digitalmars-d at puremagic.com
Fri Feb 24 05:11:53 PST 2017
In keeping with "design by introspection" I've been wanting to
write library code that statically inspects the abilities of the
entities it's passed and reacts accordingly. Unfortunately, this
approach tends to hide implementation mistakes: there's no
general way to distinguish between "this function doesn't support
calling with an array" v.s. "this function has a typo in it when
called with an array". The result is that the code generated in
the library might be either completely wrong or at least
unexpected. The error messages often appear in totally unrelated
places.
I've been working on getting a way to distinguish at the
call/instantiation site between two cases:
1) a call / instantiation couldn't find a match (e.g. failed
template constraint)
2) a call / instantiation found a match, but that match failed to
compile (e.g. implementation bug)
The code below is as far as I've got, as a potential candidate
for inclusion in std.traits if there's a way of making it work.
Two problems I'm having:
a) relies on the match being more specialised than a single
variadic template arg
b) I can't get the last unittest assert to pass and it's totally
confusing me.
Any help would be much appreciated :)
Also, if a compiler dev felt like just implementing a builtin
trait for it instead, that would be great and almost certainly
way faster to compile...
template isMatch(alias foo, TemplArgs...)
{
struct DummyT { }
template TestMatch(TestTemplArgs...)
{
DummyT TestMatch(RTArgs...)(auto ref RTArgs args)
{
return DummyT.init;
}
}
alias olSet = foo;
alias olSet = TestMatch;
bool isMatch(RTArgs...)(auto ref RTArgs args)
{
static if (__traits(isTemplate, foo))
return !is(typeof(olSet!TemplArgs(args)) == DummyT);
else
return !is(typeof(olSet(args)) == DummyT);
}
}
@safe unittest
{
template Tests()
{
static void foo0(int a);
static assert(isMatch!foo0(3));
static assert(!isMatch!foo0(3.0));
struct S { }
static S foo1();
static assert(isMatch!foo1);
static assert(!isMatch!foo1(3));
template T0() if (false) { }
static assert(!isMatch!T0);
template T1() if (true) { }
static assert(isMatch!T1);
template T2() if (false) { }
template T2() if (true) { }
static assert(isMatch!T2);
void foo2(Q = float, T = short)(T t) if (!is(Q == real)
&& !is(T == float))
{
static assert(!is(Q == T));
}
static assert(isMatch!foo2(3));
static assert(isMatch!(foo2, int, long)(3));
static assert(!__traits(compiles, foo2!(int, int)(3)));
// internal static assertion...
static assert(isMatch!(foo2, int, int)(3)); // but *is* a
match :)
static assert(isMatch!(foo2, double)(3));
static assert(!isMatch!(foo2, real)(3));
static assert(!__traits(compiles, foo2(3.0f)));
static assert(!isMatch!foo2(3.0f)); // FAILS HERE, I'm
confused
}
alias t = Tests!();
}
More information about the Digitalmars-d
mailing list