深入理解C++11 读书笔记(四) 易于编码的特性

c++11 对’>’的改进

  • c++98中如果在模板定义中Y<X<int>>这样写会编译失败,>>之间需要有空格,在C++11中已经改进,不再需要空格。

auto类型

  • 要求编译器 根据值对变量进行自动推导。因为是根据值来进行推导,因此必须是立即初始化变量,auto i;这种就非法。auto不是类型声明,而是占位符,在编译期间进行推导替换成实际类型。
  • auto的好处除了使用简单,还能避免一些隐士转换带来的精度损失。比如返回值是double,但调用方使用的是float来存储,就带来了精度损失,用auto就没有这个问题。
  • 在模板编程是带来更多好处。
template<typename T1,typename T2>
sum(T1 & t1,T2 &t2){
    auto t3 = t1 + t2;
    return t3;
}
  • 定义地址时,auto * 和auto 是一样的,如果想定义引用,必须用auto &.auto * p = &a;auto p = &a; auto & r = a
  • C++中,const和volatile一起成为cv限制符(qualifier) 。auto可以和cv一起使用,但是不能改变变量的cv。
doubel foo();
float * bar();
const auto a = foo();//const double
volatile auto &b = bar();//volatile float *
auto d = a;//double 
auto &e = a;//const double &

decltype

  • 编译时进行类型推导,经常和auto/typedef/using一起使用。
  • 使用decltype可以重用匿名类型。
  • 可以增大泛型编程的灵活性。
  • decltype只接受表达式做参数,不接受函数名做参数
  • 推导函数的返回类型是使用基于decltype的result_of模板类
    注意
int i;
decltype(i) a;//int a
decltype((i)) b;//  编译失败

编译器在进行类型推导是很复杂的,对于decltype(e),按照以下四个顺序判断
1. 如果e是没有括号的标记表达式(id-expression)或类成员访问表达式,那么decltype(e)就是e命名的实体类型。
2. 否则,假设e类型是T,如果e是一个将亡值(xvalue),则decltype(e)是T&&
3. 否则,假设e类型是T,如果e是一个左值(lvalue),则decltype(e)是T&
4. 否则,假设e类型是T,则decltype(e)是T。

int i=4;
int arr[5]={0};
int*ptr=arr;
struct S{double d;}s;
void Overloaded(int);
void Overloaded(char);//重载的函数
int&&RvalRef();
const bool Func(int);
//规则1:单个标记符表达式以及访问类成员,推导为本类型
decltype(arr)var1;//int[5],标记符表达式
decltype(ptr)var2;//int*,标记符表达式
decltype(s.d)var4;//double,成员访问表达式
decltype(Overloaded)var5;//无法通过编译,是个重载的函数
//规则2:将亡值,推导为类型的右值引用
decltype(RvalRef())var6=1;//int&&
//规则3:左值,推导为类型的引用
decltype(true?i:i)var7=i;//int&,三元运算符,这里返回一个i的左值
decltype((i))var8=i;//int&,带圆括号的左值
decltype(++i)var9=i;//int&,++i返回i的左值
decltype(arr[3])var10=i;//int&[]操作返回左值
decltype(*ptr)var11=i;//int&*操作返回左值
decltype("lval")var12="lval";//const char(&)[9],字符串字面常量为左值
//规则4:以上都不是,推导为本类型
decltype(1)var13;//int,除字符串外字面常量为右值
decltype(i++)var14;//int,i++返回右值
decltype((Func(1)))var15;//const bool,圆括号可以忽略
//编译选项:g++ -std=c++11-c 4-3-10.cpp
  • 与auto不同,decltype要带走表达式里的cv限定符,用decltype推导类成员变量时,不会继承类的cv限定符
#include <type_traits>
#include <iostream>
using namespace std;
int i=1;
int&j=i;
int*p=&i;
const int k=1;
int main(){
decltype(i)&var1=i;
decltype(j)&var2=i;//冗余的&,被忽略
cout<<is_lvalue_reference<decltype(var1)>::value<<endl;//1,是左值引用
cout<<is_rvalue_reference<decltype(var2)>::value<<endl;//0,不是右值引用
cout<<is_lvalue_reference<decltype(var2)>::value<<endl;//1,是左值引用
decltype(p)*var3=&i;//无法通过编译
decltype(p)*var3=&p;//var3的类型是int**
auto*v3=p;//v3的类型是int*
v3=&i;
const decltype(k)var4=1;//冗余的const,被忽略
}
//编译选项:g++ -std=c++11 4-3-13.cpp

追踪返回类型

  • 追踪返回类型配合auto和decltype可以释放c++的泛型编程能力。
  • 在C++98中,如果模板函数返回值依赖于参数类型,则返回值在模板实例化前都没法确定,我们在定义函数模板就会遇到麻烦。比如模板Sum(T1 t,T2 t).
    最直观的写法
template<typename T1,typename T2>
decltype(t1+t2) Sum(T1 t1,T2 t2){
    return t1+t2;
}

这种写法有问题,编译器在推导decltype(t1+t2)时,表达式t1和t2都没有声明(编译器只会从左往右读符号),c++编译器规则变量使用前必须声明,因此c++11引入新语法,追踪返回类型,来声明这类函数。

template<typename T1,typename T2>
auto Sum(T1 t1,T2 t2)->decltype(t1+t2){
    return t1+t2;
}
  • 将返回值写在参数声明之后,让编译器来推导函数模板返回类型。

基于范围的for循环

对于stl里的有明确范围的集合,可以使用for加冒号直接遍历循环

vector<int> v = {1,2,3,4,5};
for(auto i:v){
    cout<<i;
}
  • 注意使用范围循环且使用auto的话,变量表示的是解引后的对象,不是迭代器。更改变量值不会改变集合里的值,想用引用的方式得用auto &。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值