Когда вы видите различное поведение в разных компиляторах, вы, скорее всего, находитесь в области неопределенного поведения (или, возможно, просто неопределенного поведения). В этом случае неопределенное поведение происходит из-за доступа к висячей ссылке (res1
).
const auto& res1 = std::max(func(a), func(b));
Эта строка инициализирует res1
как ссылку на то, что возвращает std::max
, устанавливая возможность висячей ссылки. Априори, это просто возможность; некоторые похожие линии не создают висячих ссылок. Первый фактор, на который стоит обратить внимание, - это самая внешняя функция, std::max
. Если бы эта функция возвращала по значению (a.k.a. вернула временное), время жизни этого временного объекта было бы продлено, чтобы res1
не зависало. Однако это не так, поскольку он возвращает ссылку. Не просто ссылка, а ссылка на один из ее параметров. Тем не менее, это нормально, если возвращаемый параметр не является временным. Увы, func()
возвращает по значению, а не по ссылке. Так что мы действительно в плохом деле.
- Параметр
max
является временным.
max
возвращает ссылку на свой параметр.
Это ситуация, описанная в третьем пункте Время жизни временного @ cppreference.com. Результатом является свисающая ссылка, и доступ к ней для печати ее значения вызывает неопределенное поведение.
Может быть интересно отметить, что добавление еще одного вызова функции может разрешить неопределенное поведение:
const auto& res1 = func(std::max(func(a), func(b)));
Конечно, если бы func
было чем-то отличным от функции идентификации, это изменило бы функциональность. Но, что касается неопределенного поведения, значение, возвращаемое внешним func
, является копией временного значения, возвращаемого func(b)
. Это новое временное существо, немедленно связанное со ссылочной переменной, поэтому его время жизни увеличивается. Все хорошо.
Опять же, более типичным исправлением для этой линии будет удаление амперсанда ...
Эх, учебное упражнение.