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

?

+3


source to share


2 answers


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 call opEquals

    when T

    opEquals

    mutable.

  • Use static if

    for definition opEquals

    in different ways depending on how it is T

    defined opEquals

    .

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.

+5


source


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

.

+1


source







All Articles