第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;
}
时间: 2024-11-03 02:35:13

第3课 类型推导(3)_追踪返回类型的相关文章

Oracle PLSQL Demo - 20.弱类型REF游标[没有指定查询类型,也不指定返回类型]

declare Type ref_cur_variable IS REF cursor; cur_variable ref_cur_variable; v_ename varchar2(10); v_deptno number(2); v_sal number(7,2); v_sql varchar2(100) := 'select t.ename, t.deptno, t.sal from scott.emp t'; begin Open cur_variable For v_sql; Loo

《Effective Modern C++》读书笔记 Item 2 auto的类型推导

注意: 还要学习一个 ↑↑↑↑ 这样的方框里的片段完全不来自于原书,而是我自己的理解. Item 2 Understand auto type deduction - auto类型推导 在C++11之前,auto 关键字一直是用于声明自动储存类型的变量时使用的,基本上没有什么实际作用,地位和 export 关键字(用于向编译单元之外导出模板,也在C++11中被取消)类似. 在C++11中,auto 终于不再废材,终于具备了类似C#中 var 关键字的效果,可以自动推导出变量的类型,可以少打几个字

《Effective Modern C++》翻译--条款2: 理解auto自己主动类型推导

条款2: 理解auto自己主动类型推导 假设你已经读过条款1关于模板类型推导的内容,那么你差点儿已经知道了关于auto类型推导的所有. 至于为什么auto类型推导就是模板类型推导仅仅有一个地方感到好奇.那是什么呢?即模板类型推导包含了模板.函数和參数,而auto类型判断不用与这些打交道. 这当然是真的.可是没关系. 模板类型推导和auto自己主动类型推导是直接匹配的. 从字面上看,就是从一个算法转换到还有一个算法而已. 在条款1中.阐述模板类型推导採用的是常规的函数模板: template<ty

《Effective Modern C++》翻译--条款1: 理解模板类型推导

北京2016年1月9日13:47:17 开始第一章的翻译. 第一章名为 类型推断 分为四个条款: 1理解模板类型推导 2理解auto自动类型推导 3理解decltype操作符 4如何对待推导的类型 第一章 类型推导 C++98有一套单一的类型推导的规则用来推导函数模板.C++11轻微的修改了这些规则并且增加了两个推导规则,一个用于auto,一个用于decltype.接着C++14扩展了auto和decltype可以使用的语境.类型推导的普遍应用将程序员从必须拼写那些显然多余的类型中解放了出来,它

关于java可变(协变)返回类型的解说之一------------基类与派生类

在java代码中,人们惯性的认为一个方法中只能返回一种返回值或者无返回.博主在做开发过程中碰到了这样一种情况,安卓客户端请求数据,后台可能返回两种结果(1)访问令牌失效,无数据返回.(2)正常获取数据. 这样的情况下需要根据访问令牌标识来判断是否有数据返回.当无效时返回用户重新登录提示,正常时则返回数据.显然,返回的结果有两种,那么一个方法里面只能返回一种类型的禁锢使得开发起来略显笨拙.使得开发起来相当难受. 思考良久,又结合C++协变返回类型的启发.摘抄原文中的一句话:在C++中,只要原来的返

c/c++: c++函数返回类型什么情况带const

c++ 函数的返回类型,包括const 什么时候起作用呢? 函数返回值不想其立即修改的. 例子如下,这是一个简单的避免产生隐形返回变量的方法,abc 的函数返回是引用,main函数中第10行,++ 操作是基于 const int & 类型,所以会出错,但以后对改引用的操作不会受到const 约束. 这样的好处是避免了函数返回值与操作符的逻辑错误结合,例如下面的例子中函数返回的++,对于main 函数是不直观的,进一步的应用是在操作符重载方面,见下一情况说明. 1 const int & a

Java协变返回类型

今天看到句话:“支持重写方法时返回协变类型”. 那么什么事协变类型?在网上找了找资料,大体上明白了. Java 5.0添加了对协变返回类型的支持,即子类覆盖(即重写)基类方法时,返回的类型可以是基类方法返回类型的子类.协变返回类型允许返回更为具体的类型.示例程序如下: 代码如下: import java.io.ByteArrayInputStream; import java.io.InputStream; class Base { //子类Derive将重写此方法,将返回类型设置为InputS

常见表达式返回类型 (复习)

常见表达式返回类型总结 返回类型是一个非常重要的概念,它是指一个表达式运算结果的类型. 声明变量:void 一个变量声明的表达式,返回类型是void(无返回类型). int a // 这是一条变量声明语句,该表达式无返回类型int b = 1 // 注意,这仍然是一条变量声明语句!该表达式无返回类型 变量赋值:返回类型和变量类型相同 一条变量赋值的表达式,返回类型就是该变量的类型,返回结果就是该变量的值. int a, b;double c; // 该表达式返回类型int.返回结果1a = 1;

第2课 类型推导(2)_decltype关键字

1. decltype关键字 (1)auto所修饰的变量必须被初始化,编译器才能通过初始化来确定auto所代表的类型,即必须先定义变量. (2)decltype可以在编译期推导出一个变量或表达式的结果类型(但不会真正计算表达式的值),并且使用这个结果定义新的变量. [实例分析]获取表达式的类型 //2.1.cpp #include <iostream> using namespace std; int main() { int x = 0; decltype(x) y = 1; //y: in