I have seen that one of the always given reasons of using trailing return types is when we want to deduce the return type from the input arguments.
I know there are other reasons but I'm focusing this specific one in this question.
One of the given example is:
template <typename T>
auto func(const T & t) -> decltype(std::cout << t)
{
return std::cout << t;
}
But I could not figure out any concrete use-case of this.
I mean, we always know the return type of a function when we write it, I can't find any concrete example when deducing the return type from arguments is really needed and cannot be avoided.
We can always (if I'm not mistaken) rewrite the function's prototype by directly specifying the return type without any deduction which makes it more concise and clearer in my sense.
The above example can be rewritten as:
template <typename T>
std::ostream& func(const T & t)
{
return std::cout << t;
}
In my opinion, this is less verbose and more readable than the trailing return type version.
What am I missing ?
I mean, we always know the return type of a function when we write it
Do we? So If you write this function template:
template<typename A, typename B>
/* ret */ foo(A a, B b) {
return a + b;
}
You can say for sure what ret
is? If given two integer then it's an integer, sure. But if provided an integer and a long, it should be long due to promotions. And if one argument is a double, than the result should be a double two.
And what if that's two objects of some class types? Now we are calling an overloaded operator+
, and there's absolutely no guessing what it may return.
I hope your'e convinced now that by saying we accept any two types, we cannot always be sure what is the type of an expression involving those types.
So a mechanism was added to the language to tell. Granted, this example is overly simple and is likely superseded by auto
return types, but the general principle remains. When writing generic code, we often deal with unknown types. There is almost no knowing what should be the type of an expression involving them, or even if an expression like that is valid before the function is instantiated. decltype
tells us that.