On Tuesday, 12 October 2021 at 09:30:57 UTC, Johann Lermer wrote:
> Hi all,
I have a problem with Tuples and struct templates that contain an alias this:
import std;
struct Element(T)
{
T payload;
alias payload this;
this (T p)
{
payload = p;
}
}
class Item {}
void main ()
{
auto e = Element!Item (new Item());
auto t = tuple(e);
}
dmd generates a warning: Warning: struct Element has method toHash, however it cannot be called with const(Element!(Item)) this.
Element.toHash defined here: /usr/local/include/d/druntime/import/object.d(83)
The culprit seems to be the 'alias payload this'. When I remove that line, the code works. However, in my code, I need that alias. Any ideas, what's wrong or what I could do? Thanks.
All classes in D inherit from Object
, and Object
has a toHash
method. So what's happening here is (1) your Item
class is inheriting toHash
from Object
, and (2) your Element
struct is "inheriting" toHash
from Item
via alias this
. This is why the compiler says, "struct Element
has method toHash
".
For historical reasons, Object.toHash
is not a const
method, which means it cannot be called on a const(Object)
. So if you had a const(Element!Item)
and you tried to call .toHash
on it, the compiler would rewrite the call to .payload.toHash
using alias this
, and then it would fail to compile, because payload
would be a const(Item)
(a subclass of const(Object)
). This is why the compiler says, "however, it cannot be called with const(Element!(Item))
".
The simplest fix is to define a toHash
method for Element
using the built-in hashOf
function:
size_t toHash() const
{
return hashOf(payload);
}