逃离“inout hell”

问题描述 投票:3回答:2

我有一些非常简单的代码拒绝编译:

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());
}

现在,我知道这个问题,即Test没有定义inout opEquals。但是,在opEquals中定义Test的另一个可变版本并不能解决这个问题,因为编译器只是忽略它并且无论如何调用inout版本。有没有办法让我解决这个问题而不诉诸为mutable,opEqualsconst定义一个immutable重载?

d
2个回答
5
投票

所有inout都是为了使返回类型的常量可以匹配函数参数的常量。如果你有

const(Foo) bar(const(Foo) f) {
{
    //...
    return f;
}

并且你将mutableimmutable对象传递给bar,你最终返回了一个const对象,而如果你使用inout

inout(Foo) bar(inout(Foo) f) {
{
    //...
    return f;
}

返回类型与传递给f的参数具有相同的常量。无论哪种方式,在函数内,f被有效地视为const。你只能在它上面调用constinout函数。因此,制作opEquals inout毫无意义,因为它不会返回任何论点。它与制作const相同。

这里你的根本问题是你试图在const对象上调用一个可变函数。这不合法,因为它违反了const。您有以下两种选择之一:

  1. WrapperopEquals可变。然后它可以在opEqualsT可变时调用opEquals
  2. 根据static if如何定义opEquals,使用T来定义opEquals

没有办法将opEqualsT的常量转发到Wrapper,而没有明确地使用static if。例如

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;
        }
    }
}

因为Wrapper是一个模板,purenothrow@safe将根据其函数推断,但constinoutimmutable没有属性推断。


0
投票

只需删除inout。编译器会自动为模板推断const等属性。

你还没有将inout用于其预期用途; inout用于根据函数的参数将mutable,const或immutable传递给函数的返回类型。函数体必须假设最坏(const),因此它不能调用非常量方法。

请注意,因为在您的示例中,Test.opEquals不是const,所以只能在可变对象上调用它。另请注意,在D中,const是传递性的,因此const(Wrapper!Test)const(Wrapper!(const(Test)))相同。所以不管怎样,你不能在const / immutable对象上调用Test.opEquals(即使在包装器中),除非你把它变成const

© www.soinside.com 2019 - 2024. All rights reserved.