MSVC++ 2013 позволяет присваивать временные объекты, эффективно обрабатывая их как lvalues
Я сталкивался с этой "особенностью" в MSVC++, и теперь я не уверен, является ли это ошибкой или мое понимание lvalues /rvalues в C++ просто неверно.
Для иллюстрации я добавил немного заглушенного кода, но в основном проблема в том, что MSVC++ 2013 (как базовый, так и компилятор CTP NOV 2013) позволяет присваивать временные объекты, которые должны быть действительно значениями и, следовательно, запрещать любые попытки присваивания во время компиляции.,
#include <iostream>
struct account {
int value;
explicit account(int v) : value{ v } {
std::cout << "account ctor: " << value << std::endl;
}
account(const account & acc) : value{ acc.value } {
std::cout << "account copy ctor" << std::endl;
}
account(account && acc) : value{ acc.value } {
std::cout << "account move ctor" << std::endl;
}
account & operator=(const account & acc) {
value = acc.value;
std::cout << "account copy assign" << std::endl;
return *this;
}
account & operator=(account && acc) {
value = acc.value;
std::cout << "account move assign" << std::endl;
return *this;
}
};
int get_int() { return 42; }
account get_account() {
return account(123);
}
int main() {
//get_int() = 5; // this predictably fails to compile
// with '=' : left operand must be l-value
// everything below succeeds
get_account() = account(42); // console trace for this
// account ctor: 42
// account ctor: 123
// account move assign
account(123) = account(42); // console trace same as above
account acc(0); // account ctor: 0
account(42) = acc; // account ctor: 42
// account copy assign
get_account() = acc; // console trace same as above
}
конечно get_account() = acc;
или же account(42) = acc;
не предписанное поведение C++ Standard?! И то и другое get_account()
& account(42)
должно привести к значениям, которые по определению не позволяют присваивания.
Кстати, перегрузка функций-членов на основе квалификаторов lvalue / rvalue
...
void memberFn() const &;
void memberFn() &&;
...
который поддерживается в NOV 2013 CTP не работает должным образом или вообще. Я предполагаю, что это результат неспособности распознать значения, так что this
всегда lvalue.
PS К сожалению, у меня нет возможности проверить это с другими компиляторами.
1 ответ
Насколько я понимаю, это совершенно верно C++11.
Только встроенное присваивание prvalues запрещено.
Из [5, expr]:
Примечание. Операторы могут быть перегружены, то есть заданы значения при применении к выражениям типа класса (раздел 9) или типа перечисления (7.2). Использование перегруженных операторов преобразуется в вызовы функций, как описано в 13.5. Перегруженные операторы подчиняются правилам синтаксиса, указанным в разделе 5, но требования типа операнда, категории значения и порядка вычисления заменяются правилами для вызова функции.
Итак, требования по
get_account() = account(42);
такие же, как и при любом другом вызове функции-члена
get_account().foo_bar(account(42));
что имеет смысл, так как это просто более хороший синтаксис для
get_account().operator=(account(42));
Раздел 3.10, посвященный Lvalues и rvalues, ясно показывает это [basic.lval]:
Например, встроенные операторы присваивания ожидают, что левый операнд является lvalue, а правый операнд является prvalue, и в результате получается lvalue. Определяемые пользователем операторы являются функциями, а категории значений, которые они ожидают и получают, определяются их параметрами и типами возвращаемых данных.