D: Почему opIndex не является константным в классе std.container.Array?

Недавно я хотел использовать std.container.Array и приступил к созданию класса с функцией-членом getter, которая возвращает значение из класса Array. Я быстро понял, что не могу квалифицировать свой геттер как const, так как opIndex — это изменяемая функция.

Я попытался изменить исходный код на const-qualify Array.opIndex, и он отлично сработал. Однако некоторые модульные тесты в std.algorithm не прошли, жалуясь, что возвращаемое значение Array.opIndex не является lvalue.

Вот код для Array.opIndex:

ref T opIndex(size_t i)
{
    version (assert) if (!_data.refCountedStore.isInitialized) throw new RangeError();
    return _data._payload[i];
}

Есть ли что-то, что мне здесь не хватает? Почему это не const-qualified?


person David Eränen    schedule 18.08.2014    source источник


Ответы (1)


Существует ряд проблем с константно-корректными контейнерами, так как const делает так, что они не могут ничего изменить в своих внутренних компонентах, в отличие от C++, где вы можете сделать некоторые вещи mutable такими длинными. так как вы убедились, что функции логически const. IIRC, есть операции, которые выполняет Array, которые теоретически могут быть const, но не могут быть связаны с тем, как работают некоторые из его внутренних компонентов. И меня не удивит, если из-за этого люди, которые работали над этим, ничего из этого не сделали const, даже если некоторые из них могли бы быть.

Что касается opIndex, то я не вижу в этой реализации ничего очевидного, что не могло бы быть const, а то, что она вообще скомпилирована, подразумевает, что она может работать. Однако, если вы это сделаете, вам нужно перегрузить его, а не просто сделать эту конкретную перегрузку const, иначе вы не сможете назначить ей - предположительно, на что жаловался std.algorithm. Итак, вам нужно что-то вроде

ref T opIndex(size_t i) {...}
ref const(T) opIndex(size_t i) const {...}

так что он все еще работает, чтобы назначить ему - например. arr[5] = "foo"; - пока Array не const. Однако, поскольку многие из операций Array не могут быть const из-за того, как работает его реализация, я не знаю, насколько действительно полезно делать такие функции, как opIndex const, потому что вы будете очень ограничены в том, что вы можете делать с const Array!T, даже если каждая функция-член, которая может быть const, имеет const.

person Jonathan M Davis    schedule 18.08.2014
comment
Спасибо за ответ Джонатан! - person David Eränen; 19.08.2014
comment
Вы правы в том, что я не могу просто изменить исходную перегрузку на const, мне нужно добавить еще одну. Вы также правы в том, что он должен возвращать ref const(T), а не ref T. Модульные тесты по-прежнему работают с этим изменением! Возможно, эту версию const следует добавить в код? - person David Eränen; 19.08.2014
comment
И просто для уточнения: я не хотел, чтобы opIndex был константным, чтобы иметь возможность использовать его с константным массивом Array!T; вместо этого я хотел иметь возможность квалифицировать мою функцию-член getter, которая использует Array.opIndex как доступную только для чтения. - person David Eränen; 19.08.2014
comment
@DavidEränen Ну, вы используете const Array!T, если вы используете opIndex внутри функции const структуры или класса, членом которого он является, но если все, что вы пытаетесь сделать, это использовать opIndex, а не использовать его как const в В общем, похоже, что его можно легко заставить работать. Вы можете открыть запрос на улучшение issues.dlang.org или даже создать запрос на вытягивание, если вы чувствует себя смелым github.com/D-Programming-Language/phobos . Похоже, что, вероятно, следует проделать больше работы, чтобы сделать Array константно-корректным, даже если мы не можем сделать его полностью константно-корректным. - person Jonathan M Davis; 19.08.2014