Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A trailing return type is a C++11 function declaration syntax where the return type is specified after the function’s parameter list, rather than preceding the function name. It utilizes the auto keyword as a leading syntactic placeholder and the -> operator to denote the actual return type.

Syntax

// Traditional declaration
return_type function_name(parameter_list);

// Trailing return type declaration
auto function_name(parameter_list) -> return_type;

Technical Mechanics

The auto Placeholder When used with a trailing return type, the leading auto keyword acts strictly as a parser directive. It indicates to the compiler that the return type is not missing, but rather deferred to the end of the signature. Lexical Scoping and Name Lookup In a traditional function declaration, the return type undergoes name lookup before the compiler parses the parameter list. Consequently, the parameter names are not yet in scope during the name lookup phase of a leading return type. In a trailing return type declaration, name resolution for the return type occurs after the parameter list. Therefore, the function’s parameters are in scope and visible to expressions within the return type.
// 'a' and 'b' are in scope for name lookup within decltype
auto add(int a, double b) -> decltype(a + b) {
    return a + b;
}
Furthermore, trailing return types alter class scope injection for out-of-line member function definitions. Because the trailing return type is parsed after the function name and its class qualifier (e.g., MyClass::), name lookup for the trailing return type occurs within the scope of the class. This permits the use of nested types, enumerations, or aliases defined within the class without requiring redundant class name qualifiers.
class MyClass {
public:
    struct NestedType { int data; };
    NestedType process();
};

// Traditional: Requires MyClass:: qualifier on the return type
MyClass::NestedType MyClass::process() {
    return {1};
}

// Trailing: Class scope is injected after MyClass::, so NestedType is directly visible
auto MyClass::process() -> NestedType {
    return {1};
}
Lambda Expressions Trailing return types are the exclusive syntax allowed for explicitly specifying the return type of a lambda expression. Traditional leading return types cannot be parsed in lambda declarations.
// Explicitly specifying 'double' as the return type for a lambda
auto divide = [](int a, int b) -> double {
    return static_cast<double>(a) / b;
};
CV-Qualifiers and Reference Modifiers When applying const, volatile, or reference modifiers (&, &&) to member functions, the trailing return type follows the parameter list but precedes the function body. The cv-qualifiers and reference qualifiers for the implicit this pointer must be placed before the -> operator.
class Example {
public:
    // 'const' modifies the member function, placed before the trailing return type
    auto get_value() const -> int {
        return value;
    }
private:
    int value;
};
Complex Type Declarations Trailing return types isolate the return type as a distinct type-id at the end of the declaration, separating it from the function identifier. While this visually simplifies signatures for functions returning pointers to arrays or pointers to functions, the trailing type-id itself still adheres to standard C++ parsing rules and precedence. The type-id follows standard inside-out reading rules; for example, the parentheses around the pointer * in int(*)[10] remain mandatory to prevent the compiler from parsing it as an array of pointers.
// Traditional: Returns a pointer to an array of 10 integers
int (*get_array_ptr())[10];

// Trailing: Isolates the type-id, but standard precedence still applies to int(*)[10]
auto get_array_ptr() -> int(*)[10];

// Traditional: Returns a pointer to a function taking an int and returning a double
double (*get_func_ptr())(int);

// Trailing: Isolates the type-id, but standard precedence still applies to double(*)(int)
auto get_func_ptr() -> double(*)(int);

Interaction with C++14 Return Type Deduction

In C++14 and later, the -> operator and the trailing type can be omitted entirely, allowing the compiler to deduce the return type from the return statement(s) in the function body. If the -> operator is present, the compiler enforces the specified trailing type. However, the trailing return type itself can be auto or decltype(auto). In these cases, the compiler still performs return type deduction despite the presence of the -> operator.
auto func_deduced() { return 5; }                            // C++14: Deduces 'int'
auto func_trailing() -> double { return 5; }                 // C++11: Explicitly 'double', no deduction
auto func_trailing_deduced() -> decltype(auto) { return 5; } // C++14: Deduction occurs via trailing type
Master C++ with Deep Grasping Methodology!Learn More