On Sunday, 23 December 2018 at 18:53:15 UTC, Vijay Nayar wrote:
You're right, it does compile. I'm a bit surprised. I wonder if
this is a relatively recent improvement in the language,
because last time I ran into this I had no such luck. But after
seeing that your example did work, I figured one could try to
get the best of both worlds by using a strongly-typed wrapper
function in one's class. So far it seems to work:
import std.traits;
class A(KeyT, alias HashF) {
// Strongly-typed wrapper around template value parameter
'HashF'.
static size_t hash(in KeyT key) {
return HashF(key);
}
static this() {
static assert(isCallable!HashF, "Hash function is not
callable!");
static assert(Parameters!(HashF).length == 1, "Hash
function must take 1 argument.");
static assert(is(Parameters!(HashF)[0] : const(KeyT)),
"Hash parameter must be const.");
static assert(is(typeof(HashF(KeyT.init)) : size_t),
"Hash function must return size_t type.");
}
KeyT data;
size_t getHash() const {
return hash(data);
}
}
void main() {
auto a = new A!(int, (int a) => cast(size_t) a);
a.data = 5;
a.getHash();
}
I'm not sure, whether you need the static this() part at all, as
all of the asserts the compiler should do even when they are
absent...
by isCallable you restrict the HashF to not use IFTI
by calling HashF(key) you ensure implicitely, that
Parameters!(HashF).length == 1
by having hash(in KeyT key) defined with an "in" you ensured,
that HashF does not mutate the argument
and by defining size_t getHash() you ensured the return type of
HashF...