我有一些非常简单的代码拒绝编译:
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());
}
Run Code Online (Sandbox Code Playgroud)
现在,我知道问题,这是Test没有定义的问题inout opEquals.但是,定义另一个可变版本的opEqualsin Test不能解决这个问题,因为编译器只是忽略它并且inout无论如何调用版本.有没有办法让我解决这个问题,而不需要opEquals为mutable 定义一个重载const,和immutable?
所有这些inout都是为了使返回类型的常量可以匹配函数参数的常量.如果你有
const(Foo) bar(const(Foo) f) {
{
//...
return f;
}
Run Code Online (Sandbox Code Playgroud)
并且你传递一个mutable或一个immutable对象bar,你得到一个const返回的对象,而如果你使用inout
inout(Foo) bar(inout(Foo) f) {
{
//...
return f;
}
Run Code Online (Sandbox Code Playgroud)
返回类型与传递给的参数具有相同的常量f.无论哪种方式,在函数内,都f被有效地视为const.您只能在其上呼叫const和inout运行.因此,制作opEquals inout毫无意义,因为它不会返回任何参数.它与制作它是一样的const.
这里你的根本问题是你试图在一个const对象上调用一个可变函数.这不合法,因为它违反了const.您有以下两种选择之一:
制作Wrapper的opEquals可变.然后,它可以调用opEquals时T的opEquals是可变的.
用于static if根据定义的方式进行opEquals不同的T定义opEquals.
有没有办法来转发的常量性opEquals来自T于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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
由于Wrapper是一个模板,pure,nothrow,和@safe将在其职能推断,但没有属性推断const,inout或immutable.