can pass an int and a double....
You can have multiple template types in a template function, yes:
template <typename LHT, typename RHT>
// ... function definition
...and it just returns the greater one
So what would the return type of this function be? The return type is part of every function declaration, and it must be determined at compile time. So the return type can't depend on the values of the arguments passed to it.
You could have the following:
template <typename LHT, typename RHT>
LHT findGreater(LHT lhs, RHT rhs) { // ...etc...
...which assumes that LHT
is an acceptable return type; you will lose precision if LHT
is integral but RHT
is floating.
In C++11 and beyond, you could use decltype
, which should prevent you from losing precision:
template <typename LHT, typename RHT>
auto findGreater(LHT lhs, RHT rhs) -> decltype(lhs + rhs) { // ...etc...
Here, I've used the +
operator because it resolves to the higher-precision type regardless of the order of the arguments.
But what if instead of +
, you just used decltype((lhs > rhs) ? lhs : rhs)
? Here, by simply copying the body of the function into the decltype
expression, you're essentially telling the compiler "the return type that is returned by this function," which is...what, exactly?
Well, the type of a ternary expression is a common type of its arguments; in the case of the built-in numeric types, this means that the lower-precision type will be promoted. So this appears to be equivalent to using +
.
However, in C++ (unlike in C), ternary operators can evaluate to lvalues; decltype
always deduces reference type for lvalues, so if LHT
and RHT
are the same type, the function will return a reference to either lhs
or rhs
.
There are two ways around this:
- In C++14 and beyond, you can leave off the
decltype
, as long as the function is defined where it is declared. auto
does not deduce reference-type for the lvalue ternary operator evaluation.
Use std::decay
on the decltype
to ensure that it does not resolve to a reference:
template <typename LHT, typename RHT>
auto findGreater(LHT lhs, RHT rhs)
-> typename std::decay<decltype((lhs > rhs) ? lhs : rhs)>::type
{
return (lhs > rhs) ? lhs : rhs;
}
Pass your arguments by reference and intentionally return a reference. This would look like this:
template <typename LHT, typename RHT>
auto& findGreater(LHT& lhs, RHT& rhs)
{
return (lhs > rhs) ? lhs : rhs;
}
Note that I have explicitly chosen auto&
as the return type here. This ensures that the return type is a reference type even if LHT
and RHT
are different types (i.e. if decltype((lhs > rhs) ? lhs : rhs)
does not evaluate to reference type). This is apparently not viable in C++11; see comments below.