Является ли результат броска значимым?
Позволять
int a = 0;
Тогда это (int)a
значение в стандарте C++?
Разные компиляторы показывают разные результаты для этого кода:
#include <iostream>
using namespace std;
void f(int& x)
{
cout << "l value" << endl;
}
void f(int&& x)
{
cout << "r value" << endl;
}
int main()
{
int a = 0;
f((int)a);
}
компиляторы с разными результатами:
3 ответа
Значение должно быть значением r, но веб-компилятор работает с Visual Studio, а Visual Studio имеет расширение, позволяющее привязывать временные объекты к неконстантным ссылкам lvalue. ошибка / расширение, которое в этом случае использует его для генерации lvalue. Как указывает выше Игорь, это можно отключить с помощью /Za
( увидеть это в прямом эфире).
Мы можем видеть, что это должно быть rvalue (в частности, prvalue) из черновика стандартного раздела C++ 5.4
Явное преобразование типов (приведенная нотация) параграф 1, который говорит (выделение мое):
Результат выражения (T) cast-expression имеет тип T. Результатом является lvalue, если T является ссылочным типом lvalue или ссылкой rvalue на тип функции, и xvalue, если T является ссылкой rvalue на тип объекта; в противном случае результат является prvalue. [Примечание: если T является неклассовым типом, который квалифицирован cv, то квалификаторы cv игнорируются при определении типа результирующего значения; см. 3.10. —Конечная записка]
И gcc, и clang приводят к rvalue, который является ожидаемым результатом.
Кроме того, я бы порекомендовал использовать http://rextester.com/ поверх веб-компилятора, так как rextester позволяет вам делиться вашей программой, а также имеет прямой доступ.
Обновить
Бен Фойгт указывает на это сообщение об ошибке, и поэтому кажется, что Visual Studio фактически выдает lvalue. Так что это не просто случай расширения, которое позволяет временным объектам быть привязанными к неконстантным ссылкам lvalue.
Как указывает dyp, у gcc также есть расширение cast to lvalue.
Обновление 2
Mgetz подал отчет об ошибке, ответ был таков: это исправлено с помощью флага /Zc:rvalueCast, описание флага следующее:
Если указана опция /Zc:rvalueCast, компилятор правильно идентифицирует ссылочный тип rvalue как результат операции приведения в соответствии со стандартом C++11. Если этот параметр не указан, поведение компилятора такое же, как в Visual Studio 2012. По умолчанию параметр /Zc:rvalueCast отключен. Для соответствия и устранения ошибок при использовании приведений мы рекомендуем использовать /Zc:rvalueCast.
Неясно, будет ли этот флаг включен по умолчанию в будущих версиях.
Да, результатом приведения к типу объекта является значение r, как указано в C++11 5.4/1:
Результатом является lvalue, если
T
является ссылочным типом lvalue или ссылкой rvalue на тип функции и xvalue, если T является ссылкой rvalue на тип объекта; в противном случае результат является prvalue.
В стандарте C++ int(a)
а также (int)a
являются значениями (другие ответы содержат стандартные ссылки).
В вашем примере кода используется ошибка / расширение в MSVC, но не то, на что это похоже на первый взгляд. Как мы видим из этого кода, который работает в MSVC:
#include <iostream>
int main()
{
int x = 0;
(int)x = 1;
std::cout << x << std::endl;
}
MSVC лечит (int)x
как lvalue.
Несмотря на то, что MSVC имеет расширение, позволяющее привязывать значения r к неконстантным ссылкам; это расширение по-прежнему делает ссылки на rvalue более подходящими, чем ссылки на lvalue для значений rvalue.