С++ возвращает неконстантную ссылку из константного объекта

У меня есть структура, содержащая ссылку в ней

template <class T>
struct RefContainer {

    RefContainer(T& t) : _r(t) {}

    T& getRef() {
        return _r;
    }

private:
    T& _r;
};

Теперь другой объект, который неизменен, использует эту структуру внутри себя и имеет в себе этот объект следующим образом:

RefContainer<char> _c;

Когда я использую этот неизменяемый объект для преобразования самого себя с помощью точки, я получаю ссылку на константу. Поскольку я вызываю getRef объекта RefContainer внутри неизменяемых объектов, компилятор говорит, что я нарушаю корректность константы.

Сам RefContainer должен содержать неконстантную ссылку lvalue, но я бы хотел связать вызовы неизменяемого объекта для создания новых, например:

ImmubableObject obj;
auto newObj = obj.copyWithSomeAttributes().modifyWithThisString("str");
// I'm on C++11 btw, so I can use everything C++11 has to offer

Как мне сделать это «правильным» способом (возможно, избегая уродливых константных приведений)?


person Vanilla Face    schedule 16.09.2014    source источник
comment
добавьте версию const или перегрузите, если нужно иметь такое же имя (const T& getConstRef() const { return _r }) и используйте это в случаях, когда вы не хотите менять returned T&   -  person NetVipeC    schedule 16.09.2014
comment
@avakar Это было бы ужасно.   -  person Shoe    schedule 16.09.2014
comment
@Jeffrey, нет, есть причина, по которой const не является транзитивным по отношению к указателям и ссылкам.   -  person avakar    schedule 16.09.2014
comment
@avakar О чем ты?   -  person Shoe    schedule 16.09.2014
comment
Что означает, что ImmubableObject неизменен? Означает ли это, что это определение типа для какого-то const T?   -  person Shoe    schedule 16.09.2014
comment
@ Джеффри - не совсем так. Это означает, что когда я создаю этот объект, его поля никогда не должны были изменяться, и единственный способ получить разные версии этого объекта — создать новые с другими полями.   -  person Vanilla Face    schedule 16.09.2014
comment
@VanillaFace Могу ли я увидеть определение этого класса?   -  person Shoe    schedule 16.09.2014
comment
Если ImmumableObject действительно должен быть неизменным, он должен быть ImmumableObject const obj; (возможно, с некоторыми аргументами конструктора)   -  person M.M    schedule 16.09.2014


Ответы (1)


Вы должны попробовать что-то вроде этого:

template <class T>
struct RefContainer {

    RefContainer(T& t) : _r(t) {}

    T& getRef() const {
             // ^^^^^
        return _r;
    }

private:
    T& _r;
};

Таким образом, ссылка T& может использоваться как непостоянная, независимо от того, является экземпляр RefContainer объектом const или нет.

person πάντα ῥεῖ    schedule 16.09.2014
comment
Вам не нужно это mutable. На самом деле это не разрешено. - person T.C.; 16.09.2014
comment
@Т.С. Я не был уверен в этом и на самом деле не пробовал код. Я вижу, изменение ссылки в любом случае не будет разрешено. - person πάντα ῥεῖ; 16.09.2014
comment
Я не уверен, что это нормально. Вы эффективно нарушаете константность. - person Shoe; 16.09.2014
comment
@Jeffrey Это было бы так, если бы он возвращал ссылку на элемент данных. - person juanchopanza; 16.09.2014
comment
@Jeffrey Вы эффективно нарушаете const-корректность. Нет, не нарушаю. Если RefContainer будет держать const T& _r; да. Но на самом деле он просто оборачивает (не константную!) ссылку, не более и не менее. Правильная обработка состояния остается за ссылкой, а не за контейнером. - person πάντα ῥεῖ; 16.09.2014
comment
@ πάνταῥεῖ Но на самом деле он просто оборачивает (не константную!) ссылку. Таким образом, семантика RefContainer такая же, как и T&. Но семантика const RefContainer отличается от const T&. - person Shoe; 16.09.2014
comment
Решение этого аргумента заключается в том, что OP необходимо указать, должен ли const RefContainer обернуть константную ссылку. Мне кажется, что в его посте указано, что он должен содержать неконстантные ссылки. - person M.M; 16.09.2014
comment
@Jeffrey Семантические проблемы должны решаться для реальных случаев использования, которые четко не указаны в ОП. Синтаксически совершенно допустимо выдавать неконстантные ссылки из экземпляров константного класса/структуры. - person πάντα ῥεῖ; 16.09.2014
comment
@πάνταῥεῖ Что ты имеешь в виду? - person Shoe; 16.09.2014
comment
@Jeffrey Что ты имеешь в виду? О чем ты споришь? - person πάντα ῥεῖ; 17.09.2014
comment
@ πάνταῥεῖ Я не понимаю, что вы подразумеваете под семантическими проблемами, которые следует решать для реальных случаев использования. Не могли бы вы объяснить это мне? - person Shoe; 17.09.2014
comment
@Jefffrey Нет никаких семантических проблем, таких как Но семантика const RefContainer не совпадает с const T&, указанной в вопросе, насколько я понимаю. Задача ОП - сказать, действительно ли это семантическая проблема (чего я пока не вижу из вопроса). - person πάντα ῥεῖ; 17.09.2014
comment
@ πάνταῥεῖ На самом деле это семантическая проблема языка. Я бы ожидал, что RefContainer будет иметь ссылочную семантику, но это не так, если он последует вашему предложению. - person Shoe; 17.09.2014
comment
@Jeffrey На самом деле это семантическая проблема языка. Нет, почему? Конечно, есть допустимые варианты использования, и если нет, то не должен ли компилятор решить это, чтобы запретить это делать? - person πάντα ῥεῖ; 17.09.2014
comment
@ πάνταῥεῖ Главным образом потому, что в C ++ T и const T должны быть семантически разными, при этом разрешенные действия const T в большинстве случаев являются подмножеством T. В этом случае и RefContainer, и const RefContainer имеют одинаковую семантику, и это действует как изменяемая ссылка. Когда у вас есть const T, который действует как изменяемый Y, значит, у вас что-то не так. - person Shoe; 17.09.2014
comment
@Jeffrey Джеффри Это, конечно, точная семантика std::reference_wrapper. - person T.C.; 17.09.2014
comment
@Jeffrey Семантика RefContainer<T> const такая же, как и у T& const, которая совпадает с T&. Семантика T const& такая же, как и у RefContainer<T const>. - person Oktalist; 17.09.2014
comment
@Т.С. Не поддавайтесь апелляции к авторитетам. - person Shoe; 17.09.2014
comment
@Oktalist такие же, как у T& const, который совпадает с T& No. Семантика T& и T const& сильно отличается. - person Shoe; 17.09.2014
comment
@Jeffrey T& const (что может произойти только с помощью аргумента typedef или шаблона) и T const& также сильно различаются. - person T.C.; 17.09.2014