Trailing return type (C++11)

Note: IBM supports selected features of C++11, known as C++0x before its ratification. IBM will continue to develop and implement the features of this standard. The implementation of the language level is based on IBM's interpretation of the standard. Until IBM's implementation of all the C++11 features is complete, including the support of a new C++11 standard library, the implementation may change from release to release. IBM makes no attempt to maintain compatibility, in source, binary, or listings and other compiler interfaces, with earlier releases of IBM's implementation of the new C++11 features.

The trailing return type feature removes a C++ limitation where the return type of a function template cannot be generalized if the return type depends on the types of the function arguments. For example, a and b are arguments of a function template multiply(const A &a, const B &b), where a and b are of arbitrary types. Without the trailing return type feature, you cannot declare a return type for the multiply function template to generalize all the cases for a*b. With this feature, you can specify the return type after the function arguments. This resolves the scoping problem when the return type of a function template depends on the types of the function arguments.

Read syntax diagramSkip visual syntax diagram
Trailing return type syntax

>>-function_identifier--(--+-----------------------+--)--------->
                           '-parameter_declaration-'      

>--+------------------+--+-----------------------+-------------->
   '-cv_qualifier_seq-'  '-exception_declaration-'   

>-- -> -return_type--------------------------------------------><

Notes:
  • This syntax is not the one for a function declaration or definition. The auto placeholder occurs in the syntax for declarations and definitions where they specify return_type_specifier.
  • As with function declarators without a trailing return type, this syntax might be used to declare a pointer or reference to function.
  • More complex types might be formed by using the syntax of direct_declarator in place of function_identifier. For the details of direct_declarator, see Overview of declarators.

To use the trailing return type feature, declare a generic return type with the auto keyword before the function identifier, and specify the exact return type after the function identifier. For example, use the decltype keyword to specify the exact return type.

In the following example, the auto keyword is put before the function identifier add. The return type of add is decltype(a + b), which depends on the types of the function arguments a and b.
// Trailing return type is used to represent 
// a fully generic return type for a+b.
template <typename FirstType, typename SecondType> 
auto add(FirstType a, SecondType b) -> decltype(a + b){
   return a + b;
}

int main(){
   // The first template argument is of the integer type, and
   // the second template argument is of the character type.
   add(1, 'A'); 

   // Both the template arguments are of the integer type.
   add(3, 5); 
}
Notes:
  • When a trailing return type is used, the placeholder return type must be auto. For example, the statement auto *f()->char results in a compile-time error, because auto * is not allowed as the placeholder return type.
  • The auto type specifier can be used with a function declarator with a trailing return type. Otherwise, the auto type specifier is used in accordance to the auto type deduction feature. For more information about auto type deduction, see The auto type specifier (C++11). Because a function declaration cannot have an initializer as required for auto type deduction, the auto type specifier cannot be used in a function declaration without a trailing return type. For declarations of pointers and references to functions, the auto type specifier can be used with either a corresponding trailing return type or an initializer. For details of pointers and references to functions, see Pointers to functions.
  • The return type of a function cannot be any of the following types:
    • Function
    • Array
    • Incomplete class
  • The return type of a function cannot define any of the following types:
    • struct
    • class
    • union
    • enum
    However, the return type can be any of these types if the type is not defined in the function declaration.
In addition, this feature makes your program more compact and elegant in cases where functions have complicated return types. Without this feature, programs might be complicated and error prone. See the following example:
template <class A, class B> class K{
   public: 
      int i;
};

K<int, double> (*(*bar())())() {
   return 0;
}
You can use the trailing return type feature to make the code compact. See the following example:
template <class A, class B> class K{
   public: 
      int i;
};

auto bar()->auto(*)()->K<int, double>(*)(){
   return 0;
}
This feature can also be used for member functions of classes. In the following example, the program is concise because the return type of the member function bar does not need to be qualified after using a trailing return type:
struct A{
   typedef int ret_type;
   auto bar() -> ret_type;
};

// ret_type is not qualified
auto A::bar() -> ret_type{  
   return 0;
}
Another use of this feature is in writing perfect forwarding functions. That is, the forwarding function calls another function, and the return type of the forwarding function is the same as that of the called function. See the following example:
double number (int a){
   return double(a);
}

int number(double b){
   return int(b);
}

template <class A> 
auto wrapper(A a) -> decltype(number(a)){
   return number(a);
}

int main(){
   // The return value is 1.000000.
   wrapper(1); 

   // The return value is 1.
   wrapper(1.5); 
}
In this example, the wrapper function and the number function have the same return type.