I saw the example code for template function max.
template <typename T1,
typename T2,
typename RT = std::decay_t<decltype(true ? std::declval<T1>()
: std::declval<T2>())>>
RT max (T1 a, T2 b) {
return b < a ? a : b;
}
I know what is decltype
and declval
. But I couldn't understand why it uses ternary operator with always true to deduce return type.
If I use max(1, 2.5)
it returns double
type of 2.5
, which means RT
is deduced to second parameter T2
or double
. How is it possible even though decltype
returns only type of T1
?
(I know I can use auto
for return type to simplify code. But my purpose is to understand the usage of weird code.)
std::decay_t<decltype(true ? std::declval<T1>() : std::declval<T2>())>
is a way of obtaining the "common type" of T1
and T2
. Presumably, if T1 = int
and T2 = double
, this is intended to be double
because int
would be converted to double
in an expression such as int{...} + double{...}
.
See What is the result type of '?:' (ternary/conditional operator)?
Note that std::declval
returns an rvalue reference, and std::decay_t
removes that reference qualification so that RT
is not a reference, but an object type.
More commonly, people use std:common_type_t
which uses the conditional operator as one of the ways of obtaining a common type.
template <typename T, typename U, typename R = std::common_type_t<T, U>>
R max(T a, U b) {
return b < a ? a : b;
}
Or alternatively:
// C++20 abbreviated function template
// C++11 trailing return type with decltype
auto max(auto a, auto b) -> decltype(b < a ? a : b) {
return b < a ? a : b;
}