Trailing return type (C++11)
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
- 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.
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);
}
- When a trailing return type is used, the placeholder return type
must be
auto
. For example, the statementauto *f()->char
results in a compile-time error, becauseauto *
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, theauto
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, theauto
type specifier cannot be used in a function declaration without a trailing return type. For declarations of pointers and references to functions, theauto
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
template <class A, class B> class K{
public:
int i;
};
K<int, double> (*(*bar())())() {
return 0;
}
template <class A, class B> class K{
public:
int i;
};
auto bar()->auto(*)()->K<int, double>(*)(){
return 0;
}
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;
}
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.