Return Type Deduction (C++14)
Automatic return type deduction for functions and lambdas
The Evolution of Return Types
C++98/03
Explicit return types only
C++11
Trailing return types (decltype)
C++14
Automatic return type deduction
Before C++14: Explicit Types
// C++98/03: Must specify return type explicitly
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
// C++11: Trailing return type for complex cases
template<typename T, typename U>
auto multiply(T a, U b) -> decltype(a * b) {
return a * b;
}C++14: Auto Return Type
C++14 allows auto as the return type, with the compiler deducing the actual type from the return statements.
// C++14: Automatic return type deduction
template<typename T, typename U>
auto add(T a, U b) {
return a + b; // Return type is decltype(a + b)
}
// Regular functions too
auto get_value() {
return 42; // Returns int
}
auto get_pi() {
return 3.14159; // Returns double
}Multiple Return Statements
When multiple return statements exist, they must all deduce to the same type:
// Valid: All returns deduce to int
auto get_number(bool flag) {
if (flag) {
return 1; // int
}
return 0; // int (same type)
}
// ERROR: Mixed return types
auto bad_function(bool flag) {
if (flag) {
return 1; // int
}
return 3.14; // double - ERROR!
}Return Type Deduction Rules
- autoReturns by value (removes cv-qualifiers and references)
- auto&Returns lvalue reference (preserves reference)
- const auto&Returns const lvalue reference
- decltype(auto)Preserves cv-qualifiers and references exactly (C++14)
decltype(auto) - Preserving Type Information
Use decltype(auto) when you need to preserve references and cv-qualifiers:
template<typename Container>
auto get_first(Container& c) -> decltype(auto) {
return c.front(); // Preserves reference type
}
std::vector<int> vec = {1, 2, 3};
get_first(vec) = 100; // Works! Returns int&
// With plain auto, this wouldn't work:
template<typename Container>
auto get_first_auto(Container& c) {
return c.front(); // Returns int (copy), not int&
}Recursive Functions
Return type deduction doesn't work with recursive functions without a forward declaration:
// ERROR: Cannot deduce return type for recursion
auto factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1); // Error: factorial not yet defined
}
// SOLUTION 1: Forward declaration with trailing return
template<typename T>
auto factorial(T n) -> T {
if (n <= 1) return T{1};
return n * factorial(n - 1);
}
// SOLUTION 2: C++23 deducing this (see later chapter)
auto factorial = [](this auto&& self, int n) -> int {
if (n <= 1) return 1;
return n * self(n - 1);
};Best Practices
- ✓Use
autoreturn type for simple, obvious cases - ✓Use
decltype(auto)when forwarding returns - ✓Prefer explicit return types for public API functions (clearer interface)
- ✗Don't use auto return when the type is not obvious from context
- ✗Avoid mixing different return types in the same function