Введение: приведение в стиле C эквивалентно (C ++ 17 [expr.cast]):
int& r = const_cast<int&>( static_cast<const int&>(Func()) );
В подвыражении static_cast<const int&>(Func())
описывается поведениеC ++ 17 [expr.static.cast] / 4 (где T
- это тип, который приводится к типу):
Если T
является ссылочным типом, эффект тот жекак выполнение объявления и инициализации T t(e);
для некоторой изобретенной временной переменной t
(11.6), а затем использование временной переменной в результате преобразования
В этом случае T
равно const int&
, поэтому инициализация ссылки похожа на const int& t(Func());
.
Теперь в этом коде есть две проблемы:
- Тип временного
- время жизни вовлеченного временного
Тип временного const int
(C ++ 17 [dcl.init.ref] /5.2.1.2).Таким образом, ваш код вызывает неопределенное поведение, изменяя объект const. Ссылка на другой вопрос SO по этой теме
В остальной части этого ответа (обращаясь к проблеме на всю жизнь) я предполагаю, что вы измените r = 5
на какое-то утверждение, которое только читает r
.
Поведение цепочки ссылок изменилось с применением CWG 1299 .Дефект был зарегистрирован в апреле 2011 года и устранен в марте 2017 года. Решение не появилось в C ++ 17 (N4659);оно появляется только в черновиках после C ++ 17.
Разрешение имеет статус DRWP, мое понимание этого заключается в том, что оно означает, что оно задним числом применяется к C ++ 17, но не к C ++ 14 (если кто-тохочет подтвердить или исправить это, что было бы замечательно).
В любом случае, это разрешение позволяет в некоторых случаях увеличивать срок службы по ссылочным цепочкам.Формулировка (N4762 class.tevent / 6):
[...] Временный объект, к которому привязана ссылка, или временный объект, который является полным объектом подобъекта, к которому относитсяссылка сохраняется в течение всего срока жизни ссылки, если значение , к которому привязана ссылка , было получено одним из следующих способов:
- [...]
- a
const_cast
, static_cast
, dynamic_cast
или reinterpret_cast
преобразование без определяемого пользователем преобразования операнда glvalue, который является одним из этих выражений, в glvalue, который относится к объекту, указанному операндомили к его полному объекту или подобъекту,
До CWG1299 этот параграф применялся только для инициализации ссылки из prvalue, но теперь он может применяться к случаям инициализации ссылки излюбая категория выражений, если обозначенный объект является временным объектом.
Обратите внимание, что способ временная материализация работает в C ++ 17, заключается в том, что prvalue преобразуется в xvalue, когда происходит материализация, и это xvalue является glvalue, на который ссылается жирный текст выше.
Теперь есть даже пример, подтверждающий это:
const int& b = static_cast<const int&>(0);
// временное int имеет то же время жизни, что и b
В поведении компиляторов, показанных в другом удаленном ответе, должно применяться разрешение CWG1299.