Skip to content

Modern C++ • Return type deduction

Another small but convenient extension to C++11 is the possibility of using the auto specifier to tell the compiler to work out the return type of ordinary functions. For example, in the following code

auto f(int x)
{
   return x*x;
}

the compiler will correctly infer the type returned by f() as an int. This is also possible for forward declarations, that is the following statement is perfectly valid

auto f(int x);

however, the function cannot be used until its body is defined. Return type deduction has also been extended for lambda expressions. In fact, one limitation of C++11’s lambdas was the fact that its return type (if none was specified) could only be deduced if the lambda’s body consisted of only a return statement, in which case the return type was inferred from the returned expression, otherwise it was considered to be void. The following code, for example, was ill-formed

int g(int x) { return x; }

auto f = [](int x)
{
   auto y = g(x);
   return y;
}

In order for it to work, a trailing-return-type had to be provided, as in the below code

auto f = [](int x) -> int
{
   auto y = g(x);
   return y;
}

With C++14 all lambda expressions have an auto return type by default (if none is specified) that’s not limited to bodies with a single return statement. If multiple return statements exist they must all resolve to the same type, otherwise the program is ill-formed. Also, C++11 forbade the use of auto in trailing-return-types, which meant that returning deduced reference types could not be possible. C++14 eliminated this restriction, so that we can now write

auto f = []() -> auto& { return g(); }

to specify that a lambda returns a deduced reference type. Return type deduction also works for templates, as shown in the following code

template <typename T>
auto& f(T& x)
{
  return x;
}
Published inModern C++