3.1.6 Return Type Deduction

What was the problem

The decltype specifier was added in C++11 to identify the type of an expression [2.1.8]. One of its typical use cases is the declaration of the return type in a template function whose result type must be deduced from the template arguments.

// This function is a proxy to call a given function with the given 
// arguments. Its return type depends on the provided function. 
template<typename F, typename... Args> 
auto invoke(F&& f, Args&&... args) -> decltype(f(std::forward<Args>(args)...)) 
{ 
  return f(std::forward<Args>(args)...); 
}

Note how the expression passed to decltype is exactly the body of the function.

How the Problem is Solved

To avoid this verbosity, C++14 allows to omit the trailing return type to let the compiler deduce the type from the function’s body.

template<typename F, typename... Args> 
auto invoke(F&& f, Args&&... args) 
{ 
  return f(std::forward<Args>(args)...); 
}

An excellent use case for this feature is a function returning a lambda [2.1.7]. Have you ever tried to write one?

auto make_comparator(int v) -> /* what should I write here? */ 
{ 
  return [v](int c) -> bool 
  { 
    return v == c; 
  }; 
}

As far as I know there is no way to write such a function in C++11. In C++14, though, we can simply drop the return type and let the compiler deduce it from the body.

Guideline

One could be tempted to always omit the return type under the false assumption that less code is more readable. Don’t do that.

Whenever we omit the return type, the reader has to parse the whole body to find the actual type. This is needlessly complex and makes painful code reviews. What should be more readable actually requires to process more code.

Implied information are bad in programming. Don’t follow the “modern C++” trend which pushes for using every new feature everywhere; use them only when you need them.