Так как это самый популярный вопрос в отношении этой проблемы, я снова опубликую здесь еще один ответ:
Похоже, что есть более простой способ сделать это (но только в MySQL):
select *
from (select * from mytable order by id, rev desc ) x
group by id
Пожалуйста, прокомментируйте ответ пользователя Bohemian в на этот вопрос за предоставление такого краткого и элегантного ответа на эту проблему.
EDIT: хотя это решение работает для многих людей, оно может быть нестабильным в долгосрочной перспективе, поскольку MySQL не гарантирует, что оператор GROUP BY вернет значимые значения для столбцов, не входящих в список GROUP BY. Поэтому используйте это решение на свой страх и риск
Насколько я могу судить, вы действительно правы, это выглядит как «ошибка» , хотя, честно говоря, это недавно изменилось с дефектом CWG 1213 , в котором говорится:
Поскольку операция субтипирования определяется как косвенное наведение по значению указателя, результат оператора индекса, применяемого к массиву xvalue, является значением lvalue, а не значением x. Это может быть удивительно для некоторых.
blockquote>, и это изменило раздел 5.2.1 [expr.sub] следующим образом:
Постфиксное выражение, за которым следует выражение в квадратных скобках - постфиксное выражение. Одно из выражений должно иметь тип «массив Т» или «указатель на Т», а другой должен иметь неперечисленное перечисление или интегральный тип. Результатом является lvalue типа «T». Тип «T» должен быть полностью определенным типом объекта.62 Выражение E1 [E2] идентично (по определению) к * ((E1) + (E2)) [ Примечание: см. 5.3 [expr.unary] и 5.7 [expr.add] для получения подробных сведений о * и + и 8.3.4 [dcl.array] для получения подробной информации о массивах. -End note], за исключением того, что в случае операнда массива результат равен lvalue, если этот операнд является lvalue и xvalue иначе.
blockquote>Так что действительно результат
f().a[0];
иstatic_cast<S&&>(s).a[0]
должны быть x значениями.У этого дефекта не было предлагаемой резолюции до декабря 2012 года, а поддержка отчета о дефектах clangs перечисляет поддержку этого отчета о дефектах как неизвестную, поэтому, скорее всего, разработчики не получили исправления
Обновить
Подано сообщение об ошибке clang : Оператор подстроки, примененный к временному массиву, приводит к lvalue .
Я могу проверить в Clang 3.4.1 std = c ++ 11.
Вот мои выводы:
int i = f().a[0]
будет верным: вы получаете ссылку на временная структура, время жизни временного увеличивается на длительность ссылки, вы принимаете значение: fine.
int *i = &f().a[0]
принимается компилятором. Тем не менее, предупреждение f
о том, что вы возвращаете ссылку на локальный временный объект , имеет смысл здесь. Время жизни временного объекта увеличивается на время ссылки: здесь время для копирования адреса. Как только вы берете адрес a
, содержащий объект исчезает, и у вас есть только оборванная ссылка .
int *i = f().a
- это точно такой же случай, как и предыдущий.
Но когда вы делаете &f().a
, вы принимаете адрес rvalue типа 'int [3]' , и нет смысла брать такой адрес : вы можете использовать только его значение.
Давайте перейдем еще дальше:
S s = f();
верен. Вы получаете ссылку на временную структуру, время жизни временного расширения на длительность ссылки, вы принимаете значение: fine.
Теперь &s.a[0]
является четко определенным указателем на int
, as is int *ix2 = &static_cast<S&&>(s).a[0];
Вы даже можете записать: int (*ix3)[3] = &s.a;
, чтобы принять адрес массива до 3 int
, но по той же причине вы не можете написать &static_cast<S&&>(s).a
, потому что вы адрес rvalue типа 'int [3]'
TL / DR
С S s = f();
s.a
является четко определенным значением r, s.a[0]
является корректным значением lvalue (вы можете написать s.a[0] = 5;
).
f().s
является rvalue, но с его помощью будет вызываться UB, потому что он заканчивается ссылкой на временный объект, который будет быть уничтожен, прежде чем вы сможете его использовать.
f().s[0]
может использоваться как хорошо определенное значение rvalue. Вы можете использовать его как lvalue, но по той же причине, что и выше, он будет вызывать UB.