首页 > 代码库 > 第3课 类型推导(3)_追踪返回类型

第3课 类型推导(3)_追踪返回类型

1. 追踪返回类型的引入

(1)经典问题:泛型编程中的返回值类型(被迫引入了返回值类型R作为模板参数)

template<typename R, typename T, typename U>
R add(T t, U u)
{
    return t + u;
}

int a = 1; float b = 2.0
auto c = add<decltype(a+b)>(a,b); //不能自动推导函数的返回值。为了获得返回值的类型,该函数的使用者需要知道add函数的内部实现(如:a+b)

(2)decltype的尴尬

template<typename R, typename T, typename U>
decltype(t + u) add(T t, U u)  //编译出错,因为编译器是从左向右读入符号,而返回值是前置语法,定义返回值时t、u参数尚未定义。
{
    return t + u;
}

(3)不完美的解决方案——写法过于晦涩难懂

template<typename R, typename T, typename U>
decltype((*(T*)0) + (*(U*)0)) add(T t, U u)  //技巧:利用0地址进行类型转换
{
    return t + u;
}

2. 返回类型后置(trailing-return-type, 又称为追踪返回类型

(1)利用追踪返回类型声明进行的等价函数声明

  ①函数指针的等价:如,auto (*fp)() -> int 与int (*fp)()的等价;

  ②函数引用的等价:如,auto  (&fr)() -> int 与 int (&fr)()的等价

(2)利用auto + decltype的结合进行追踪返回类型

template<typename R, typename T, typename U>
auto add(T t, U u) -> decltype(t + u) //返回类型后置
{
    return t + u;
}

【实例分析】使用追踪返回类型的函数

//3.1.cpp

#include <iostream>
using namespace std;

//1. 追踪返回值类型
template<typename T1, typename T2>
auto Add(const T1& t1, const T2& t2) ->decltype(t1 + t2)
{
    return t1 + t2;
}

template<typename T1, typename T2>
auto Mul(const T1& t1, const T2& t2) ->decltype(t1 * t2)
{
    return t1 * t2;
}

//2. 晦涩的面试题
int (*(*pf())())(){
    return nullptr;
}

//pf1是个函数,无参,返回值类型是auto(*)() ->int (*)()
//而auto(*)() ->int (*)表示是一个函数指针(具体类型可按同样的
//方法从右向左解析出来)
auto pf1() -> auto(*)() -> int (*)(){
    return nullptr;
}

//函数转发
double foo(int a){
    return (double)a + 0.1;
}

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

template<typename T>
auto Forward(T t) -> decltype(foo(t)){ //根据实际调用的foo(t)追踪其返回值类型
    return foo(t);
}

int main()
{
    ////////////////////////////////////////////////////
    //1. 追踪返回值类型(该例比较特殊,没有指明任何的具体类型)
    //   更像是动态类型语言的代码,而不像严格静态类型的C++代码
    auto a = 3;
    auto b = 4L;
    auto pi = 3.14;
    
    auto c = Mul(Add(a, b), pi);
    cout << c << endl; //21.98
    
    ////////////////////////////////////////////////////
    //2. 简化函数定义
    cout << is_same<decltype(pf), decltype(pf1)>::value<< endl; //1,pf和pf1函数的类型完全相同!
    
    //3. 转发函数
    cout << foo(2) << endl;
    cout << foo(0.5) << endl;
    
    cout << Forward(2) << endl;
    cout << Forward(0.5) << endl;
    
    return 0;
}

第3课 类型推导(3)_追踪返回类型