尾部返回类型 (C++11)

注: IBM 支持 C++11的所选功能,在批准之前称为 C++0x 。 IBM 将继续开发和实施此标准的功能部件。 语言级别的实现基于 IBM对标准的解释。 在完成 IBM对所有 C++11 功能部件的实现 (包括对新的 C++11 标准库的支持) 之前,实现可能会随着发行版而更改。 IBM 不会尝试在源代码,二进制或列表以及其他编译器接口中维护与 IBM的先前发行版实现新的 C++11 功能部件的兼容性。

如果返回类型取决于函数自变量的类型,那么尾部返回类型功能将除去 C++ 限制,其中无法对函数模板的返回类型进行泛化。 例如,ab是函数模板的自变量multiply(const A &a, const B &b),其中ab属于任意类型。 如果没有尾部返回类型功能,那么不能声明multiply用于泛化所有案例的函数模板a*b使用此功能,可以在函数自变量后指定返回类型。 这将在函数模板的返回类型取决于函数自变量的类型时解决作用域限定问题。

Trailing return type syntax

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

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

>-- -> -return_type--------------------------------------------><
注:
  • 此语法不是函数声明或定义的语法。 自动占位符在其指定return_type_说明符的声明和定义的语法中出现。
  • 与没有尾部返回类型的函数声明符一样,此语法可用于声明函数的指针或引用。
  • 可以使用direct_声明符的语法来代替 function_identifier ,从而形成更复杂的类型。 有关direct_声明者的详细信息,请参阅 声明者概述

要使用尾部返回类型功能,请使用以下命令声明通用返回类型:auto在函数标识之前指定关键字,并在函数标识之后指定精确的返回类型。 例如,使用decltype关键字以指定精确的返回类型。

在以下示例中,auto关键字放在函数标识之前add. 返回类型adddecltype(a + b),这取决于函数自变量的类型ab.

// 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); 
}

注:

  • 使用尾部返回类型时,占位符返回类型必须为auto. 例如,语句auto *f()->char导致编译时错误,因为auto *不允许作为占位符返回类型。
  • auto类型说明符可与具有尾部返回类型的函数声明符配合使用。 否则,auto根据自动类型扣除功能使用类型说明符。 有关自动类型扣除的更多信息,请参阅 自动类型说明符 (C++11)。 由于函数声明不能具有自动类型扣除所需的初始化方法,auto不能在没有尾部返回类型的函数声明中使用类型说明符。 对于指针的声明和对函数的引用,auto类型说明符可以与相应的尾部返回类型或初始化方法配合使用。 有关指向函数的指针和引用的详细信息,请参阅 指向函数的指针
  • 函数的返回类型不能是以下任何类型:
    • 功能
    • 数组
    • 不完整的类
  • 函数的返回类型无法定义以下任何类型:
    • 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不需要在使用尾部返回类型后进行限定:

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); 
}

在此示例中,wrapper函数和number函数具有相同的返回类型。