CodeNebula
C++14coreintermediate

Return Type Deduction for Functions

C++14 · Modern Refined · Compiler flag: -std=c++14

Explanation

Functions declared with `auto` as the return type have their return type deduced by the compiler from the `return` statement. This removes redundancy in function signatures, especially for templates and short utility functions where the return type mirrors the expression type.

Real-World Scenario

A math library provides a generic `clamp` function that works with any numeric type, and the return type is automatically deduced to match the input type without repeating a trailing return type.

Quick Snippet

snippet.cpp
#include <iostream>

auto add(int a, int b) {
    return a + b; // return type deduced as int
}

template<typename T>
auto square(T value) {
    return value * value; // return type deduced from T
}

int main() {
    std::cout << add(3, 4) << "\n";         // 7
    std::cout << square(2.5) << "\n";       // 6.25
}

Full Example

return_type_deduction.cpp
// CodeNebula - C++14 Example: Return Type Deduction
// Compile: g++ -std=c++14 -Wall -Wextra -o example return_type_deduction.cpp

// Demonstrates auto return type deduction for regular functions in C++14.
// Unlike C++11's trailing return types, C++14 lets the compiler deduce
// the return type from the return statement. Real-world use: simplifying
// template code, factory functions, and wrapper functions.

#include <iostream>
#include <string>
#include <vector>
#include <tuple>

// ------------------------------------------------------------------
// 1. Simple auto return - compiler deduces 'int'
// ------------------------------------------------------------------
auto square(int x)
{
    return x * x;
}

// ------------------------------------------------------------------
// 2. Auto return with different types based on input
// ------------------------------------------------------------------
auto describe(int value)
{
    if (value > 0)
        return std::string("positive");
    else if (value < 0)
        return std::string("negative");
    else
        return std::string("zero");
    // All return paths must yield the same type
}

// ------------------------------------------------------------------
// 3. Auto return in template functions
// ------------------------------------------------------------------
template<typename T, typename U>
auto multiply(T a, U b)
{
    return a * b;   // deduced as common type of T*U
}

// ------------------------------------------------------------------
// 4. Auto return with complex types (avoids verbose typenames)
// ------------------------------------------------------------------
auto make_pair_vector()
{
    std::vector<std::pair<std::string, int>> result;
    result.push_back({"alpha", 1});
    result.push_back({"beta", 2});
    result.push_back({"gamma", 3});
    return result;  // deduced as vector<pair<string,int>>
}

// ------------------------------------------------------------------
// 5. Recursive function with auto return (must have base case first)
// ------------------------------------------------------------------
auto factorial(int n) -> int   // recursive needs trailing return or forward decl
{
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

// ------------------------------------------------------------------
// 6. Auto return with lambda-like brevity
// ------------------------------------------------------------------
auto clamp(int value, int lo, int hi)
{
    return (value < lo) ? lo : (value > hi) ? hi : value;
}

int main()
{
    std::cout << "=== Simple Auto Return ===" << std::endl;
    std::cout << "  square(7)  : " << square(7) << std::endl;
    std::cout << "  square(-3) : " << square(-3) << std::endl;
    std::cout << std::endl;

    std::cout << "=== String Return Deduction ===" << std::endl;
    std::cout << "  describe(5)  : " << describe(5) << std::endl;
    std::cout << "  describe(-2) : " << describe(-2) << std::endl;
    std::cout << "  describe(0)  : " << describe(0) << std::endl;
    std::cout << std::endl;

    std::cout << "=== Template Auto Return ===" << std::endl;
    std::cout << "  multiply(3, 4.5)   : " << multiply(3, 4.5) << std::endl;
    std::cout << "  multiply(2.0, 3.0) : " << multiply(2.0, 3.0) << std::endl;
    std::cout << std::endl;

    std::cout << "=== Complex Return Type Deduction ===" << std::endl;
    auto pairs = make_pair_vector();
    for (const auto& p : pairs)
        std::cout << "  " << p.first << " -> " << p.second << std::endl;
    std::cout << std::endl;

    std::cout << "=== Recursive with Auto Return ===" << std::endl;
    std::cout << "  factorial(6) : " << factorial(6) << std::endl;
    std::cout << "  factorial(10): " << factorial(10) << std::endl;
    std::cout << std::endl;

    std::cout << "=== Clamp Function ===" << std::endl;
    std::cout << "  clamp(15, 0, 10) : " << clamp(15, 0, 10) << std::endl;
    std::cout << "  clamp(-5, 0, 10) : " << clamp(-5, 0, 10) << std::endl;
    std::cout << "  clamp(7, 0, 10)  : " << clamp(7, 0, 10) << std::endl;

    return 0;
}

/*
Expected output:

=== Simple Auto Return ===
  square(7)  : 49
  square(-3) : 9

=== String Return Deduction ===
  describe(5)  : positive
  describe(-2) : negative
  describe(0)  : zero

=== Template Auto Return ===
  multiply(3, 4.5)   : 13.5
  multiply(2.0, 3.0) : 6

=== Complex Return Type Deduction ===
  alpha -> 1
  beta -> 2
  gamma -> 3

=== Recursive with Auto Return ===
  factorial(6) : 720
  factorial(10): 3628800

=== Clamp Function ===
  clamp(15, 0, 10) : 10
  clamp(-5, 0, 10) : 0
  clamp(7, 0, 10)  : 7
*/
Run command
g++ -std=c++14 -Wall -Wextra -o example return_type_deduction.cpp