Ответ 1
Вот соответствующие стандартные кавычки:
12.8 пункт 32:
Копирование разрешений разрешено в следующих случаях: [...]
- в выражении
return
в функции с типом возвращаемого класса, когда выражение является именем энергонезависимого автоматического объекта (кроме функции или параметра catch-clause) с тем же CV-неквалифицированным типом, что и возвращаемый тип функции, операцию копирования/перемещения можно опустить, построив автоматический объект непосредственно в возвращаемое значение функции- [when
throw
ing, с условиями]- [когда источник является временным, с условиями]
- [при
catch
по значению, с условиями]
пункт 33:
Когда критерии для выполнения операции копирования выполняются или выполняются, за исключением того факта, что исходный объект является параметром функции, а подлежащий копированию объект определяется значением lvalue, разрешением перегрузки, чтобы выбрать конструктор для копия сначала выполняется так, как если бы объект был обозначен rvalue. Если сбой при перегрузке или если тип первого параметра выбранного конструктора не является ссылкой rvalue на тип объекта (возможно, cv-qualified), разрешение перегрузки выполняется снова, считая объект как lvalue. [Примечание. Это двухступенчатое разрешение перегрузки должно выполняться независимо от того, произойдет ли копирование. Он определяет вызывающий конструктор, если elision не выполняется, и выбранный конструктор должен быть доступен, даже если вызов отменяется. - конечная нота]
Так как выражение в return (cond ? a : b);
не является простым именем переменной, оно не подходит для копирования или элитной обработки. Может быть, немного неудачно, но легко представить, как растянуть пример немного дальше, пока вы не создадите головную боль ожидания для реализаций компилятора.
Вы можете, конечно, обойти все это, явно указав std::move
возвращаемое значение, если вы его знаете.