Почему T () = T () позволен?

Я верю выражению T() создает rvalue (по Стандарту). Однако следующие компиляции кода (по крайней мере, на gcc4.0):

class T {};

int main()
{
    T() = T();
}

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

Но концептуально это похоже на присвоение нового значения к rvalue. Существует ли серьезное основание, почему это позволяется?

Править: Причина я нахожу это нечетным, она строго запрещается на встроенных типах, все же позволенных на пользовательских типах. Например, int(2) = int(3) не скомпилирует, потому что это - "недопустимый lvalue в присвоении".

Таким образом, я предполагаю, что реальный вопрос, это несколько непоследовательное поведение было встроено в язык по причине? Или это там по некоторой исторической причине? (Например, это было бы концептуально более звуковым, чтобы позволить только функциям членства константы быть вызванными на rvalue выражения, но это не может быть сделано, потому что это могло бы взломать некоторый существующий код.)

18
задан curiousguy 25 December 2011 в 17:39
поделиться

5 ответов

Вот почему можно реализовать несколько классов в стандартной библиотеке. Рассмотрим, например, std :: bitset <> :: operator []

// bit reference:
class reference {
  friend class bitset;
  reference();
public:
  ˜reference();
  reference& operator=(bool x);           // for b[i] = x;
  reference& operator=(const reference&); // for b[i] = b[j];
  bool operator˜() const; // flips the bit
  operator bool() const;  // for x = b[i];
  reference& flip();      // for b[i].flip();
};

reference operator[](size_t pos); // for b[i];

Если вы сделаете bits [i] = true , вы точно присваиваете какое-то значение rvalue типа класса. Прокси-сервер, возвращаемый оператором operator [] , может получить доступ к битам, которые эффективно упакованы в целые числа.

4
ответ дан 30 November 2019 в 07:44
поделиться

С одной точки зрения, это непоследовательно, но вы упускаете из виду, как это является последовательным: 1) ints и другие встроенные типы ведут себя так же, как и в C, 2) operator= на class-типах ведет себя так же, как и любой другой метод, не требуя еще одного специального случая.

Совместимость с Си высоко ценилась с самого начала развития C++, и, возможно, без нее C++ не появился бы сегодня. Так что эта часть в целом хорошая вещь.

Второй момент недооценен. Не специальная оболочка operator= позволяет бессмысленному коду "работать", но почему нас вообще волнует бессмысленный код? Мусор внутрь, мусор наружу. Текущие правила придают ему определенное значение (UB здесь было бы плохо) с незначительными затратами, насколько я видел.

С моей точки зрения, все было бы упрощено еще больше, так что int() = int() было бы разрешено. C++0x начинает двигаться в этом направлении с rvalue-ссылками, prvalues и т.д.

4
ответ дан 30 November 2019 в 07:44
поделиться

Да, вы присваиваете новое значение rvalue. Точнее, вы вызываете функцию-член operator = для rvalue. Поскольку вы не используете встроенный оператор присваивания, почему вы думаете, что это должно быть проблемой? operator = является функцией-членом класса, которая во многих отношениях аналогична любой другой функции-члену класса, включая тот факт, что ее можно вызывать для значений r.

Вам, вероятно, также следует принять во внимание тот факт, что «быть rvalue» - это свойство выражения, а не свойство объекта. Верно, что выражение T () дает значение r. Тем не менее, временный объект, созданный выражением T () , по-прежнему является объектом , к которому также можно получить доступ как lvalue.Например, некоторая другая функция-член может быть вызвана в результате присвоения, и она увидит «новое» (только что назначенное) значение временного объекта через * this lvalue

(T() = T()).some_member_function();

. Вы также можете продлите срок службы временного объекта, добавив к нему константную ссылку const T & r = T () = T (); , и значение, видимое через r , будет «новым» стоимость объекта. Как правильно заметил Йоханнес в своем комментарии, это не будет прикреплять его к временному.

7
ответ дан 30 November 2019 в 07:44
поделиться

В C++0x можно ограничить operator= работой только с l-значениями:

class T
{
public:
    T& operator=(const T&) & = default;
};
5
ответ дан 30 November 2019 в 07:44
поделиться

Это разрешено исключительно из-за перегрузки операторов и возможности того, что вы можете перегрузить оператор = для выполнения чего-то более причудливого, например, печати на консоль, блокировки мьютекса или чего угодно.

13
ответ дан 30 November 2019 в 07:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: