Break out of the "home"
I have a very simple code that refuses to compile:
struct Wrapper(T)
{
T t;
bool opEquals(inout(Wrapper) other) inout
{
return t == other.t;
}
bool opEquals(inout(T) val) inout
{
return t == val;
}
}
struct Test
{
bool opEquals(Test t)
{
return true;
}
}
void main()
{
Wrapper!Test a, b;
assert(a == b);
//Error: inout method Test.opEquals is not
//callable using a mutable object
assert(a == Test());
}
Now I know the problem that it Test
does not define inout
opEquals
. However, defining a different mutable version opEquals
in Test
does not fix this problem because the compiler simply ignores it and calls the version inout
independently. Is there a way to solve this problem without resorting to overloading definitions opEquals
for mutable, const
and immutable
?
source to share
All inout
is for does this so that the return type constant is comparable to the function argument constant. if you have
const(Foo) bar(const(Foo) f) {
{
//...
return f;
}
and you pass an object mutable
or immutable
on bar
, you get the returned object const
, whereas if you useinout
inout(Foo) bar(inout(Foo) f) {
{
//...
return f;
}
the return type has the same constant as the argument passed to f
. In any case, within a function, it is f
effectively handled as const
. You can only call functions const
and inout
. So the creation is opEquals
inout
pointless because it doesn't return any of its arguments. This is the same as doing const
.
Your main problem is when you are trying to call a mutable function on an object const
. And it is not legal because it violates const
. You have one of two options:
-
Make it
Wrapper
opEquals
mutable. Then it can callopEquals
whenT
opEquals
mutable. -
Use
static if
for definitionopEquals
in different ways depending on how it isT
definedopEquals
.
It is not possible to redirect a constant opEquals
from T
to Wrapper
without doing it explicitly with static if
. eg.
struct Wrapper(T)
{
T t;
static if(is(typeof({const T t; t == t;})))
{
bool opEquals(const Wrapper other) const
{
return t == other.t;
}
bool opEquals(const T val) const
{
return t == val;
}
}
else
{
bool opEquals(Wrapper other)
{
return t == other.t;
}
bool opEquals(T val)
{
return t == val;
}
}
}
As Wrapper
a template pure
, nothrow
and @safe
they will be displayed on its functions, but const
, inout
or immutable
there is no output attribute.
source to share
Just remove inout
. The compiler automatically passes type attributes const
for templates.
In any case, you are not using it inout
for its intended purpose; inout
is designed to pass mutable, constant, or immutable return types to functions based on its parameters. The function body must accept the worst (const), so it cannot invoke non-constant methods.
Note that since it is Test.opEquals
not in your example const
, it can only be called on a mutable object. Also note that in D, is const
transitive, so it const(Wrapper!Test)
coincides with const(Wrapper!(const(Test)))
. So no matter what, you can't call Test.opEquals
const / immutable on an object (even in a wrapper) unless you do it const
.
source to share