Я думаю, что я мог придумать пример rvalue типа массива
C++03 §4.2 N°1:
Значение l или значение типа "массив N T" или "массив неизвестной границы T" может быть преобразовано в значение типа "указатель на T". Результатом является указатель на первый элемент массива.
Что меня смущало в этом утверждении долгое время, так это то, что я не совсем понимал, что будет означать значение типа массива. То есть я не мог придумать выражение, тип которого был массивом, а результат - значением. Я прочитал эту ветку, которая в основном задает тот же вопрос, и принятый ответ "нет, нет значения типа массива". Я думаю, у меня просто может быть противоречие с этим.
C++ 03 §5.2.5 N ° 4: (о выражении E1.E2)
Если E2 является нестатическим членом данных, а тип E1 - "cq1 vq1 X", а тип E2 - "cq2 vq2 T", выражение обозначает именованный член объекта, обозначенный первым выражением. Если E1 является lvalue, то E1.E2 является lvalue.
Я предполагаю, что в противном случае это значение (при условии, что 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, потому что когда они говорят о преобразованиях функций в указатели, они упоминают только l-значения типов функций (очевидно, понимая, что таких значений не существует). Поэтому вполне вероятно, что они подумали о значениях типов массивов.
Итак, в основном мой вопрос заключается в том, придумал ли я пример значения rvalue типа массива, и если нет, пожалуйста, предоставьте правильный, который, я убежден, существует.
2 ответа
Да вы правы. Выражение является значением типа массива. Это не является недостатком - комитет знает об этом, и это было также распространенной проблемой в C89, который разрешает преобразование в указатели только для l-значений типов массивов. Как следствие, вы не можете индексировать или разыменовывать массив как f().a
, C99 исправил это, и C++ не имеет проблем с этим.
Обратите внимание, что независимо от того, является ли выражение выражением объекта, независимо от того, является ли оно значением rvalue или нет. C++03 случайно опущен, чтобы сказать, что выражение rvalue, имеющее тип массива, обозначает объект. Это было исправлено в C++0x с помощью DR # 450.
(очевидно, оценивая, что таких значений нет)
На самом деле есть значения функций. Это происходит для нестатических функций-членов, обозначаемых выражением доступа к члену класса
struct A { void f(); };
/* A().f is an rvalue of type "void()" */
int main() { A().f(); }
А это значение. Массив внутри него нет. Представьте себе случай, когда у вас есть цепочка методов для этого временного объекта - переменные внутри него живут более одного вызова метода и возвращают его, и они могут передавать ссылки (действительные на время цепочки) на другие функции. Эти функции не могут знать заранее, что они должны быть вызваны.
В последней версии черновика вы можете перегрузить функции в 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 немедленно умирает. Не уверен в моем непосредственном мнении по этому поводу, но оно определенно не подходит для оценки.