c++系列文章(6):类型别名和自动类型

类型别名

  类型别名是一个名字,它是某种类型的同义词。使用类型别名可以使复杂的类型名字变得简单明了、易于使用。c++有两种方法用于定义类型别名:typedef和using

  typedef

1
typedef double wages; //wages是double的同义词
2
typedef wages base,*p; //base是double的同义词,p是double*的同义词

  关键字typedef作为声明语句中的基本数据类型的一部分出现含有typedef的声明语句定义的不再是变量而是类型别名

  using

  c++11规定了新的别名声明关键字using。

1
using wages = double; //wagess是double的同义词
2
using p = *double; //p是double*的同义词,即指向double的指针

  声明成类型别名之后,其基本数据类型可能会发生改变,如果直接将类型别名替换成原本的样子进行理解,可能会发生错误。

1
using pstring = *char; //pstring表示指向字符的指针
2
const pstring p = nullptr; //p是一个常量指针,不能将其理解为const char*,即指向字符常量的普通指针

自动类型

  auto

  c++11引入了auto类型说明符,让编译器去分析表达式的初始值来推断类型,因此auto定义的变量必须具有初始值

1
auto item = item1 + item2; //有item1和item2相加的结果推断出item的类型

  使用auto也能在一条语句中声明多个变量,因为一条声明语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型必须一致

1
auto i = 0,*p = &i; //正确,i是整数,p是整型指针
2
auto sz = 0,pi = 3.14; //错误,sz和pi的基本数据类型不一致

  编译器推断出来的auto类型可能和初始值的类型并不完全一样,编译器会适当改变结果类型使其更符合初始化规则:
  1、对于引用类型作为初始值,编译器以引用对象的类型作为auto的类型

1
int i = 0,&r = i;
2
auto a = r; //a的类型为int

  2、auto一般会忽略顶层const,保留底层const

1
const int ci = 0,&cr = &ci; //i是一个整型常量,cr是一个常量引用
2
auto b = ci; //b是一个整数,ci的顶层const被忽略
3
auto c = cr; //c是一个整数,cr是ci的引用,而ci的顶层const被忽略
4
auto d = &ci; //d是一个指向整数常量的指针,对常量对象取地址是一种底层const
5
//如果希望推断出的auto类型是一个顶层const,需要明确指出
6
const auto e = ci; //ci的推演类型是int,而e的类型是const int

  如果将引用(或者指针)的类型设置为auto,初始值中的顶层const属性仍然保留,此时在引用(或者指针)中转化为了底层const

1
auto &f = ci; //f是一个常量引用,绑定到ci
2
auto &g = 1; //错误,不能为非常量引用绑定字面值
3
const auto &h = 1; //正确,可以外常量引用绑定字面值

  要在一条语句中定义多个变量,需要切记,符号&和*只从属于某个声明符,而非基本数据类型的一部分,因此初始值必须是同一种类型。

1
//auto的基本数据类型都是int,j是整型,k是整型引用
2
auto j = ci,&k = i; 
3
//auto的基本数据类型都是const int,m是对整型常量的引用,p是指向整型常量的指针
4
auto &m = ci,*p = &ci; 
5
//错误,i的基本数据类型是int,而ci是基本数据类型是const int
6
auto &n = i,*p = &ci;

  decltype

  如果希望从表达式的类型推断出要定义的变量的类型,但是不想用该表达式的值初始化变量,为了满足这类需求,c++11引入了decltype,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值

1
decltype(f()) sum = x; //sum的类型就是函数f()的返回类型

  decltype处理顶层const和引用(或者指针)的方式与auto有所不同。
  1、如果decltype使用的表达式是一个变量,那么该变量是什么类decltype就返回什么类型(包括顶层const和引用)

1
const int ci = 1,&cr = ci;
2
decltype(ci) x = 0; //x的类型是const int
3
decltype(cr) y = x; //y的类型是const int&,y绑定到x上
4
decltype(cr) z; //错误,z是一个引用,必须初始化

  注意:引用从来都是作为其所指对象的同义词出现的,只有用来decltype时是一个列外。
  2、如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型

1
int i = 1,*p = &i,&r = i;
2
decltype(r+0) b; //加法的结果是int类型,因此b的类型是int
3
decltype(*p) c; //错误,解引用的结果是引用类型,因此c的类型是int&,必须初始化

  如果decltype使用的表达式是一个加了括号的变量,编译器会把它当成是一个表达式,此时得到的是引用类型。

1
decltype((i)) d; //错误,d是int&,必须初始化
2
decltypr(i) e; //正确,e是int