Вы можете подумать, что
template <class T, class U>
auto x(T a, U b) -> decltype(a < b ? a : b) {
return a > b ? a : b;
}
std::cout << x<long, double>(1, 2.01) << std::endl;
std::cout << x<long, double>(5, 2.01) << std::endl;
не скомпилируется, потому что конечный тип возврата decltype(a < b ? a : b)
, то есть внутреннее выражение a < b ? a : b
не совпадает с возвращаемым выражением a > b ? a : b
, но это совершенно законно поскольку возвращаемый тип становится любым типом, следующим после ->
.
Теперь, почему следующий код не скомпилирован успешно?
template <class T, class U>
auto x(T a, U b) -> decltype(a < b ? a : a) {
return a > b ? a : b;
}
std::cout << x<long, double>(1, 2.01) << std::endl;
std::cout << x<long, double>(5, 2.01) << std::endl;
Это потому, что вам нужно удалить ссылку из конечный тип возврата, например:
#include <type_traits>
template <class T, class U>
auto x(T a, U b) -> typename std::remove_reference<decltype(a < b ? a : a)>::type {
return (a > b ? a : b);
}
Теперь он успешно компилируется. Проверьте здесь
Причина, по которой второй пример не компилируется без std::remove_reference
, заключается в том, что оба типа, являющиеся частью тернарного оператора, являются glvalue
s и здесь говорят, что:
4) Если E2 и E3 являются glvalues одного и того же типа и той же категории значения, то результат имеет тот же тип и категорию значения
, поэтому результат a < b ? a : a
равен glvalue
. Вот почему вам нужно удалить ссылку. И результат a < b ? a : b
равен prvalue
, поэтому вам не нужно удалять ссылку.