Ответ 1
Rvalues - это то, что вы получаете из выражений (полезное упрощение, взятое из стандарта C, но не сформулированное на С++ standardese). Lvalues - это "значения локатора". Lvalues можно использовать как rvalues. Ссылки всегда lvalues, даже если const.
Основное различие, о котором вы должны знать, можно свести к одному элементу: вы не можете взять адрес rvalue (опять же, не стандартное, а полезное обобщение правил). Или, говоря иначе, вы не можете установить точное местоположение для rvalue — если бы вы могли, то у вас было бы lvalue. (Однако вы можете привязать константу к rvalue, чтобы "исправить ее на месте", а 0x сильно изменило правила.)
Пользовательские типы (UDT), однако, немного особенные: вы можете преобразовать любое значение rval в 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
, кроме как через оператор присваивания, поставляемый компилятором, чтобы превратить значение r A()
в *this
. Чтобы процитировать стандарт, 12.8/10:
Если определение класса явно не объявляет оператор присваивания копии, одно объявляется неявно. Оператор присваивания неявным объявлением для класса X будет иметь вид
X& X::operator=(const X&)
И затем это продолжается с большей квалификацией и спецификациями, но это важный бит здесь. Поскольку это функция-член, ее можно вызывать на rvalues, так же как Special:: get_lvalue может быть, как если бы вы написали A().operator=(a)
вместо A() = a
.
int() = 1
явно запрещен, поскольку вы обнаружили, потому что ints не имеет оператора = реализовано таким же образом. Однако это небольшое несоответствие между типами не имеет значения на практике (по крайней мере, не так, как я нашел).
POD означает Plain Old Data и представляет собой набор требований, которые определяют использование memcpy, эквивалентно копированию. Non-POD - это любой тип, для которого вы не можете использовать memcpy для копирования (естественная противоположность POD, ничего скрытого здесь), которая, как правило, является большинством типов, которые вы напишете на С++. Будучи POD или не-POD не меняет ничего из вышеперечисленного, и это действительно отдельная проблема.