Вопрос

Может ли кто-нибудь объяснить детали в терминах rvalues, lvalues, PODs и non-PODs причина, по которой первое выражение, отмеченное ниже, является не ок, в то время как второе выражение, отмеченное ниже, в порядке?В моем понимании и int(), и A() должны быть rvalues, не так ли?


struct A {};

int main()
{
  int i;
  A a;

  int() = i; //Not OK (error).
  A() = a; //OK.

  return 0;
}

Это было полезно?

Решение

Значения R - это то, что вы получаете из выражений (полезное упрощение, взятое из стандарта C, но не сформулированное в стандартах C ++).Значения Lvalues - это "значения локатора".Значения Lvalues могут быть использованы как значения rvalues.Ссылки всегда являются значениями lvalues, даже если они const.

Основное различие, о котором вы должны знать, можно свести к одному пункту:вы не можете использовать адрес rvalue (опять же, не стандартный, но полезное обобщение правил).Или, другими словами, вы не можете зафиксировать точную Расположение для rvalue — если бы вы могли, то у вас был бы значение lvalue.(Однако вы можете привязать const& к rvalue, чтобы "зафиксировать его на месте", и 0x кардинально меняет правила.)

Пользовательские типы (UDT), однако, немного отличаются:вы можете преобразовать любое rvalue в lvalue, если интерфейс класса позволяет это:

struct Special {
  Special& get_lvalue() { return *this; }
};
void f() {
  // remember "Special()" is an rvalue
  Special* p = &Special().get_lvalue(); // even though you can't dereference the
  // pointer (because the object is destroyed), you still just took the address
  // of a temporary

  // note that the get_lvalue() method doesn't need to operate on a const
  // object (though that would be fine too, if the return type matched)
}

Нечто подобное происходит и с вашим A() = a, за исключением использования предоставляемого компилятором оператора присваивания, для преобразования rvalue A() в *this.Цитируя стандарт, 12.8/10:

Если в определении класса явно не объявлен оператор присваивания копии, объявляется один неявно.Неявно объявленный оператор присваивания копии для класса X будет иметь вид

X& X::operator=(const X&)

А затем это продолжается с дополнительными квалификациями и спецификациями, но это здесь самое важное.Поскольку это функция-член, она может быть вызвана для rvalues , точно так же, как Special::get_lvalue может быть, как если бы вы написали A().operator=(a) вместо того , чтобы A() = a.

В int() = 1 явно запрещено, как вы обнаружили, потому что ints не имеют operator=, реализованного таким же образом.Однако это небольшое расхождение между типами на практике не имеет значения (по крайней мере, не то, что я обнаружил).


POD означает Обычные Старые данные и представляет собой набор требований, которые указывают, что использование memcpy эквивалентно копированию.Non-POD - это любой тип, для которого вы не можете использовать memcpy для копирования (естественная противоположность POD, здесь ничего скрытого), который, как правило, относится к большинству типов, которые вы напишете на C ++.Быть POD или не быть POD не меняет ничего из вышеперечисленного и на самом деле является отдельной проблемой.

Другие советы

В моем понимании и int(), и A() должны быть rvalues, не так ли?

Правильно, выражение epx T() всегда является значением r для скалярных и определяемых пользователем типов T.До тех пор, пока нет const задействовано, выражение T() является изменяемое значение rvalue, если быть более точным.

Присвоение, включающее скалярные типы, требует изменяемого значение lvalue в левой части оператора присваивания.С тех пор как int() не является значением lvalue, вы не можете присвоить int().

Для пользовательских типов присваивание является специальной функцией-членом, и функции-члены также могут вызываться на значения rv (см. §3.10 раздел 10).Вот почему A().operator=(a) хорошо сформирован.

От Выполняет ли C ++ инициализацию значения POD typedef?, который цитирует Стандарт:

Выражение T(), где T - это спецификатор простого типа (7.1.5.2) для типа объекта, не являющегося полным массивом, или (возможно, с указанием cv) типа void, создает rvalue указанного типа, который инициализируется значением

Следовательно, int() является rvalue и не может быть присвоен, как вы видели в вашем первом случае.

A() не был бы спецификатором simlle-type и, таким образом, A() выдает значение lvalue

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top