Я думаю, что, возможно, я придумал пример rvalue типа array
-
27-09-2019 - |
Вопрос
C++03 §4.2 N°1:
Значение lvalue или rvalue типа “массив из N T” или “массив с неизвестной границей из T" может быть преобразовано в значение типа “указатель на T.” Результатом является указатель на первый элемент массива.
Что долгое время сбивало меня с толку в этом утверждении, так это то, что я не совсем понимал, что будет означать rvalue типа array .То есть я не смог придумать выражение, типом которого был бы массив, а результатом - rvalue .Я читал это поток, который в основном задает тот же вопрос, и принятый ответ - "нет, нет rvalue типа array".Я думаю, что у меня просто может быть противоречие по этому поводу.
C++03 §5.2.5 N°4: (речь идет о выражении E1.E2)
Если E2 является нестатическим элементом данных, и тип E1 равен “cq1 vq1 X", а тип E2 равен “cq2 vq2 T”, выражение обозначает именованный элемент объекта, обозначенный первым выражением.Если E1 является значением lvalue, то E1.E2 является значением lvalue.
Я предполагаю, что в противном случае это rvalue (при условии, что E2 не является ссылкой, этот случай рассматривается §5.2.5 N°3
) и следовательно...
struct A
{
int a[4];
};
A f()
{
A a;
return a;
}
int main()
{
f().a; //I think this is an rvalue of array type...
}
Я вижу здесь два варианта:
Вариант 1: Я прав, ура, ура, круто.В данном случае вопрос заключается в следующем:есть ли другие примеры?
Вариант 2: Я ошибаюсь, в данном случае вопрос заключается в следующем:является ли это дефектом стандарта?
Я не знаю насчет 1, но я действительно сомневаюсь насчет 2, потому что, когда они говорят о преобразованиях функции в указатель, они упоминают только lvalues типов функций (очевидно, понимая, что таких rvalues нет).Так что весьма вероятно, что они думали о rvalues типов массивов.
Итак, в основном мой вопрос заключается в том, нашел ли я пример rvalue типа array, и если нет, пожалуйста, укажите допустимый, который, я твердо верю, существует.
Решение
Да, вы правы.Выражение представляет собой rvalue типа array.Это не дефект - комитет знает об этом, и это также было распространенной проблемой в C89, который допускает преобразование в указатели только для значений lvalues типов массивов.Как следствие, вы не смогли бы проиндексировать или разыменовать массив, подобный f().a
.C99 исправил это, и у C ++ нет проблем с этим.
Обратите внимание, что независимо от того, является ли это rvalue или нет, это не зависит от того, обозначает ли выражение объект.В C ++ 03 случайно не указано, что выражение rvalue типа array обозначает объект.Это было исправлено в C ++ 0x автор: DR#450.
(очевидно, понимая, что таких значений не существует)
На самом деле существуют rvalues типов функций.Это происходит для нестатических функций-членов, обозначаемых выражением доступа к члену класса
struct A { void f(); };
/* A().f is an rvalue of type "void()" */
int main() { A().f(); }
Другие советы
Буква "А" - это rvalue.Массив внутри него - нет.Представьте себе случай, когда у вас есть цепочка методов для этого временного объекта - переменные внутри него работают для более чем одного вызова и возврата метода, и они могут передавать ссылки (действительные в течение всего срока действия цепочки) другим функциям.Эти функции не могут заранее знать, что они будут вызваны по rvalue.
В последней версии черновика вы можете перегружать функции на rvalue/ lvalue *this.Однако даже в этом случае ссылка на rvalue не преобразует содержимое того, что относится к rvalue, и я не совсем уверен, что КАКОЙ-ЛИБО компилятор в настоящее время поддерживает это, и я знаю, что MSVC этого не делает.
Фактически, используя decltype , вы можете легко определить, что компилятор называет этот массив значением lvalue .
Рассмотреть:
template<typename A, typename B> auto sum(A&& a, B&& b) -> decltype(std::forward<A>(a) + std::forward<B>(b)) {
return std::forward<A>(a) + std::forward<B>(b);
}
Это то, для чего был предназначен decltype, и он наиболее определенно проводит различие между lvalues и rvalues.В качестве альтернативы, рассмотрите это:
int main()
{
auto var = f().a;
}
Var - это значение int*.Это мгновенный сбой, так как f().a немедленно умирает.Не уверен в моем непосредственном мнении по этому поводу, но оно определенно не подходит для rvalue.