With the introduction of auto
return type in C++14, is there any real situation that trailing return type is required or it's completely obsolete in C++14 and 17?
The trailing return type feature removes a C++ limitation where the return type of a function template cannot be generalized if the return type depends on the types of the function arguments.
The return type, which specifies the type of the value that the function returns, or void if no value is returned. In C++11, auto is a valid return type that instructs the compiler to infer the type from the return statement. In C++14, decltype(auto) is also allowed.
Use auto and decltype to declare a function template whose return type depends on the types of its template arguments. Or, use auto and decltype to declare a function template that wraps a call to another function, and then returns the return type of the wrapped function.
Trailing return type gives you SFINAE support. Deduced return types never cause an error early enough to be a mere substitution failure.
This permits compilers not to have to be able to compile entire arbitrary functions bodies and then back out cleanly in order to determine if an overload applies.
Apart from where you are required to use it (and the other answers here give great examples), you can use it for clarity, for explicitly stating what the function returns. This is very important once you realize (hopefully pretty soon) that reading a code is at least as important as writing it.
consider:
auto split(gsl::cstring_span str)
{
...
...
auto tokens = std::vector<gsl::cstring_span>();
...
...
for (...) {
...
...
...
}
...
return tokens;
}
versus:
auto split(gsl::cstring_span str) -> std::vector<gsl::cstring_span>();
{
... doesn't even matter
}
I shouldn't be looking in the implementation to see what the contract of the function is. I could probably guess what the return type is by looking at the first example, but these kind of assumptions are dangerous in programming. I would have to scan the implementation to be sure of what I receive when I call the function. With the second example, I have the interface cleanly stated. I don't care of the implementation, as the name is self-explanatory and so I don't have to look in the definition at all.
Further more consider this even worst example. Lets find out what this function returns:
auto split(const char* str)
{
return split(gsl::cstring_span(str));
}
Ok, now search for that overload:
auto split(gsl::cstring_span str)
{
return split_impl(str);
}
Okey..., now lets follow that:
auto split_impl(gsl::cstring_span str)
{
return split_impl(str, ::isspace);
}
Are you f** kidding me.
So I hope you see the point.
I am not saying always use explicit return type, I am saying consider that knowing the return type should be quickly with a simple glance at the function. Sometimes, for one-liners, that can be discovered from the body. Sometimes, it can be safely guessed from the name (e.g. is_empty()
clearly returns bool
). Other times, you would need to explicitly name it. Make the developer's life who uses your code later simpler, especially since that one will eventually inevitably be you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With