On Sunday, 23 December 2018 at 18:31:24 UTC, Alex wrote:
On Sunday, 23 December 2018 at 18:13:25 UTC, Vijay Nayar wrote:
For example, if you have a const function in your container
like "T find() const", and this function needs to use that
comparator, then you're out of luck because the compiler
doesn't know that the comparator function is const and will
not modify the objects being compared.
Last time I ran into this problem, my solution was simply to
give up on const. But now I'm running into it again and trying
to think through it again before giving up again.
Hm... still not sure... ;)
This would compile and run:
´´´
import std.experimental.all;
size_t myHashFunction(int a) { return cast(size_t) a; }
void main()
{
auto b = new B!(int, myHashFunction);
b.arr = 42.iota.array;
assert(b.find == 1);
}
class B(T, alias HashF)
{
T[] arr;
T find() const
{
foreach(el; arr)
{
if(HashF(el))
{
return el;
}
}
assert(0);
}
}
´´´
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();
}