函数返回类型自动推导
函数返回类型自动推导是指C++11以及C++14中不直接给出函数返回类型,而是使用类型指示符来指示返回类型甚至彻底省略返回类型并最终由编译器来推导返回类型的语言特性。
函数返回类型自动推导原则如下:
- 当函数体内不包含任何返回值时,该函数的返回类型为void。
- 当函数体内只包含一句带返回值的return语句时,该函数的返回类型等同于该返回值的类型。
- 当函数体内包含多个带返回值的return语句时,该函数的返回类型由这些返回值的类型共同决定,所有返回值的类型必须相同。
- 函数体内的返回值可以递归调用自身,但这类无法由编译器自动推导类型的返回值,必须发生在可以由编译器自动推导类型的非递归调用的返回值之后。
在lambda表达式中省略返回类型
当lambda表达式中省略返回类型时,lambda表达式的返回类型由编译器根据返回值以及模板参数推导规则进行自动推导。
声明函数时使用auto指示符来指示返回类型
当函数的返回类型包含auto指示符并且函数的后置返回类型被省略时,函数的返回类型由编译器根据返回值以及模板参数推导规则进行自动推导。
声明函数时使用decltype(auto)指示符来指示返回类型
当函数的返回类型为decltype(auto)指示符时,函数的返回类型由编译器根据返回值以及decltype推导规则进行自动推导。
#include <iostream>
#include <string>
#include <typeinfo>
template<typename T>
T f();
auto f2(int n)
{
return n + 1;
}
auto f3(bool b)
{
if(b) return 1.0;
else return 2.0;
}
auto f4(int n)
{
if(n == 0) return 1;
else return n * f4(n - 1);
}
struct S
{
int n1, n2;
decltype(auto) f6(bool b)
{
if(b) return (n1);
else return (n2);
}
};
int main()
{
auto f1 = [](int a){std::cout << a;};
auto f5 = [](auto a, auto b){return a + b;};
f<decltype(f1(1))>();
f<decltype(f2(1))>();
f<decltype(f3(false))>();
f<decltype(f4(3))>();
f<decltype(f5(1.0f, 3.0f))>();
S s;
f<decltype(s.f6(false))>();
}
main.cpp:(.text.startup+0x5): undefined reference to `void f<void>()'
main.cpp:(.text.startup+0xa): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0xf): undefined reference to `double f<double>()'
main.cpp:(.text.startup+0x14): undefined reference to `int f<int>()'
main.cpp:(.text.startup+0x19): undefined reference to `float f<float>()'
main.cpp:(.text.startup+0x1e): undefined reference to `int& f<int&>()'
这段代码使用了一种特殊技巧来查看编译器所实际推导出的函数返回类型。代码中定义了一个未被实现的函数模板f,该函数模板有一个类型参数T。如果用某个类型T来调用该函数模板,编译器就会因找不到函数模板的定义而输出”T f<T>()未被定义“的出错信息。也就是说,利用该函数模板,我们便可以在编译器所输出的出错信息中检查模板参数T的实际类型。在main函数内,我们充分利用了这一个技巧,通过利用函数返回类型调用该函数模板来让编译器输出相应的类型。
从出错信息中可以得知:
- lambda表达式f1的返回类型被推导为void。
理由:lambda表达式的函数体内没有任何返回值。 - 函数f2的返回类型被推导为int。
理由:函数体内只包含一个return语句,返回值n+1类型为int。 - 函数f3的返回类型被推导为double。
理由:函数体内包含两个return语句,返回值1.0以及2.0类型都是double。 - 函数f4的返回类型被推导为int。
理由:函数体内包含两个return语句,其中第二个返回值递归调用自身,无法推导,而第一个返回值1类型为int。 - lambda表达式f5的返回类型被推导为表达式a+b的类型。当 a=1.0f, b=3.0f 时,f5的返回类型为表达式 1.0f + 3.0f 的类型,即float。
理由:函数体内只包含一个return语句,返回值a+b类型取决于泛型参数a以及b的类型。 - 函数f6的返回类型被推导为int&。
理由:函数体内包含两个return语句,将返回值(n1)以及(n2)代入decltype(auto)结果类型都是int&。