Почему operator++ должен возвращать const T?

211
11 ноября 2017, 13:35
const T T::operator++(int)
{
    T tmp = *this;
    ++(*this);
    return tmp;
}

Рассмотрим такой вариант реализации постфиксного оператора инкрементирования. Почему требуется возвращать именно const T, а не T? Такой вариант реализуется для типа int, а нужно ли мне реализовывать этот оператор для своего пользовательского типа аналогично?

Я придерживался негласного правила, что при разработке классов (типов) в случае если непонятно (или еще не сформулировано) требуемое поведение то следует организовать поведение, какое предоставляет int. int возвращает const int. А нужно ли и мне так?

Answer 1

Нет необходимости делать возвращаемый тип константым, чтобы избежать двойного инкремента ++++. Достаточно объявить оператор инкремента только для lvalue объектов (добавить & в сигнатуру):

struct T {
    T operator++(int) & { return *this; }
};
int main() {
    T t;
    t++;   // ok    
    t++++; // ошибка
}
Answer 2

Постфиксный оператор инкрементирования (оператор декрементирования аналогнично) возвращает const T, чтобы предотвратить потенциально некорректное использование некоторых конструкций, т.к. двойное постфиксное инк-/дек- рементирование вида i++++.

В силу особенностей реализации этого оператора возвращается прошлое значение объекта, поэтому второй вызов оператора operator++(int) изменит значение возвращенной первым оператором копии исходного объекта, а не результата с учетом первого инкрементирования.

Как правило, клиентский код обычно не требует (вообще говоря, не должен) поддержки таких конструкций, как двойное применение постфиксного оператора и одновременное изменение значения, возвращаемого постфиксным оператором, в одной инструкции, поэтому запрет подобной операции через const T вполне оправдан. Ошибок избегать это помогает точно.

Answer 3

const T в результате функции запрещает неконстантные операции, в частности перемещение (move-семантика).

struct X {
  X(X&&);
  const X operator++(int);
  int& operator*();
};
X a;
X b = a++;  // тут будет копирование, а не перемещение
*a++ = 1;  // не скомпилируется
READ ALSO
Написать sqrt через ряды Тейлора с++

Написать sqrt через ряды Тейлора с++

Добрый день! Помогите, пожалуйста реализовать функцию квадратного корня из числа через ряд Тейлора на с++: Вот некоторые похожие рабочие...

492
Как сделать генератор даты на c++ [требует правки]

Как сделать генератор даты на c++ [требует правки]

Числа будут в комбобоксах и нужно чтобы допустим если месяц такой то то дней в этом месяце столько тоже самое про год

235