C++11读书笔记—3(auto与decltype类型推导)

来源:互联网 发布:关联矩阵法案例 编辑:程序博客网 时间:2024/05/29 19:11

C++一直认为是“静态类型语言”,声明一个变量的类型再使用。而动态类型语言如python,不用声明,直接就可以用。说实话,有些时候声明类型的行为的确看似多余,如int i = 1;你仅看i = 1时,你就知道i是int型的。于是自动类型推导出现了。这里我们使用的是auto关键字。老C语言里面auto关键字可怜到基本没人用,因为他是默认设置,(都默认了谁还多写啊)。于是C++来重定义了一下。后来还有decltype。发明这些的目的其实是为了广泛用于泛型操作。最后说明下,我一直认为这样的改动仅仅算得上“伪动态类型语言。”

一、auto类型推导

1.auto初识

由于C/C++的传统,程序员都喜欢站在内存空间思考问题。auto不能真的使变量像python那样变成真动态类型。
auto a = 1;//可以推导a为intauto b = a;//推导b为intauto c;//编译失败,无法推导,变量c的内存空间不知道怎么分配c = 3;
个人感觉,auto能干的活编译器帮你检查语法时都能干,auto更像一个占位符。所以auto使用时必须赋值,否则的话都会出现不知道怎么分配内存空间的问题。那么如此有局限性的auto最大优势是什么?

2.auto的最大优势——简化代码,防止溢出,泛型适应

std::vector< std::map< int, std::vector<int, int> > > myGraph;//下面两种写法,当然是第二种更亲民。for (std::vector< std::map< int, std::vector<int, int> > >::iterator i = myGraph.begin(); i != myGraph.end(); i++) {};for (auto i = myGraph.begin(); i != myGraph.end(); i++) {};

这是一个非常值得推广的写法方式。简化代码,也避免错误。这里的< >符号过多,导致错误,也避免无用代码过度导致程序员错误。
当然,auto关键字也能防止数字加减乘除的不经意间的溢出问题。

还可以在泛型编程中避免尴尬的类型问题。
template<typename T1,typename T2>void sum(T1 a, T2 b){auto sum = a + b;}

3.auto使用

说实话刚接触auto时就知道有一种不祥的预感。标准委员会肯定又给我们挖坑了。
1.auto* 与auto 一样。因为auto也能推导出指针类型,但是auto&就不同了。auto不能推导出引用类型。同理const auto ,volatile auto。。。等都有与auto不同的含义。
2.不要真的把auto当成自动推导。下面的程序准保出问题:
auto a =1,b=0.1f;
auto当成占位符,推导从左往右,a =1时,auto就的位置被int占据了。int b=0.1f;这就精度损失了。

说说不能推导的坑吧!!!
1.函数形参绝对不行,因为这会破坏重载。
如:void f(auto i =1){};//破坏重载 
2.结构体中非静态成员变量不行,即使有初始值也不行
如,struct a{ auto var = 10;}//
3.模板参数绝对不行
vector<auto> v = {1};//编译器会发疯。
4.auto a[3] 不行
注意C++11标准中用C,C++98标准的 auto int i=10;会报错。我的vs2015报错了。

二、decltype

1.typeinfo与decltype

auto替语法检查器做了很多事情,这样的静态类型推导好像很不智能。老C++中就已经有动态类型获取函数typeid()了。这就是RTT1(运行时类型识别),为每个类型产生一个type_info,想一想就知道有多慢了。这种拖慢速度的行为会使专注效率的C程序员产生大量吐槽能量。
大家认为,在不影响功能的前期下,如果将运行时类型判断改为编译时类型判断,将会更有效率。最终标准化为decltype与auto。decltype相较于auto的是他具有函数般的性质。只不过他的返回值不是对象,而是类型。

    float a;    double b;    decltype(a+b) c;       cout << typeid(c).name() << endl; 
decltype声明变量的时可以不初始化,这点不同于auto。
这有什么用呢?之前遇到匿名类型你烦不?auto局限了的地方decltype可以弥补。还是上面那个模板。
template<typename T1,typename T2>void sum(T1 & a, T2 & b,decltype(a+b) & s){s = a + b;}
decltype内部放的是表达式。函数名什么的就不要放了。

2.decltype用法

相比起auto看来decltype更好用。按照C++惯用的套路。decltype的坑肯定更大。规则太繁杂了,我复制粘贴一下。(注意这个推导规则有很多版本,而且匹配规则要从上到下依次来)
对于decltype( e )而言,其判别结果受以下条件的影响:
1. 如果e是一个标识符或者类成员的访问表达式,则decltype(e)就是e所代表的实体的类型。
2. 如果e是一个函数调用或者一个重载操作符调用(忽略e外面的括号),那么decltype(e)就是该函数的返回类型;
3. 如果e不属于以上所述的情况,则假设e的类型是 T:当e是一个左值时,decltype(e)就是T&;如果e是个将亡值,那么decltype为T&&;
否则,decltype(e)是T。
这里的好像有什么不得了的东西。。没错这就是C++11的右值系统。下一篇会介绍右值系统。
好吧,不说完会被打的,根据书上的例子我整合下。上面的规则太繁杂了,举几个例子

#include<iostream>using namespace std;int func_int();int & func_int_r();int && func_int_rr();struct MyStruct{int x;};int main(){volatile int i = 0;const MyStruct S = MyStruct();decltype(i) i1;decltype((i)) i2 = i1;<span style="white-space:pre"></span>//加括号相当于表达式,这不是匹配规则1能解决的,用规则3。左值,故int &decltype(S.x) S_x;<span style="white-space:pre"></span>//规则1就可以decltype((S.x)) S_x1 = S_x;<span style="white-space:pre"></span>//规则1,2都不行,用3。S.x类型就是const int,故const int &decltype(func_int()) f;decltype(func_int_r()) f_r = f;decltype(func_int_rr()) f_rr = 0;return 0;}
有几个坑,注意跳就行







0 0
原创粉丝点击