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.
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:
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.