本节将介绍更多的处理类型的方法。

类型别名

类型别名(type alias)使得简化复杂的类型定义,便于使用。

类型别名的定义有两种方法。过去,我们使用typedef:

typedef double wages; // wages is a synonym for 
typedef wages base, *p; // base is for double, p for double*

C++ 11新标准引入了第二种定义类型别名的方法,即通过别名声明(alias declaration):

using SI = Sales_item; // SI is a synonym for Sales_item

语法是使用using关键字。

别名和指针,const

typedef char *pstring;
const pstring cstr = 0; // cstr is a constant pointer to char
const pstring *ps; // ps is a pointer to a constant pointer to char

这里声明的基本类型是const pstring。const出现在基本类型中,来修改给定类型。 类型pstring指向char的指针,因此,const pstring指向char的const指针,不是指向const char的指针

我们不能简单的通过"字符串替换"认为它是const char *cstr = 0;

pstring出现在声明,其基本类型就是一个指针类型。当使用char *重写声明时,基本类型是char,是类型的一部分; 于是const char是基本类型。

auto类型

这是C++ 11引入的。

有时,我们很难知道变量的具体类型,我们可以使用auto来让编译器自己确定其类型。auto告诉编译器通过初始化器确定变量类型。

要注意的是,因为一个声明只能有一个基本类型(base type),所以声明中对所有变量的基本类型必须一致。

auto i =0, *p = &i; // ok; both are int
auto sz = 0, *pi = 3.14; // error

auto和复合类型,const

int i = 0, &r = i;
auto a = r; // a is an int

第一,使用引用时,我们真正想使用的是引用绑定的对象;使用auto的类型会进行这样的转化,使之符合初始化规则。

第二,auto自动会忽略高层const,保留低层const。

const int ci = i, &cr = ci;
auto b = ci; // b is an int (top-level const is ignored)
auto c = cr; // c is an int (cr is an alias for ci whose top-level const is ignored)
auto d = &i; // d is an int*
auto e = &ci; // e is const int* (& of a const object is a low-level const)

如果我们需要高层const,可以自己指定:const auto f = ci;

同样,我们也可以指定auto解析得到类型的引用:

auto &g = ci; // g is a const int&, bound to ci
auto &h = 42; // error
const auto &j = 42; // ok: we can bind a const reference to a literal

当一条语句定义了多个变量,需要记住:引用或指针是声明的一部分,不是声明基本类型的一部分。

auto &n = i, *p2 = &ci; // error: type deduced from i is int; type deduced from &ci is const int.

decltype

有时,我们希望编译器得到一个表达式的类型,但不需要使用该表达式的值去初始化变量。这时可以使用C++ 11引入的decltype。 编译器会分析表达式的类型,但不必得到其值。

decltype(f()) sum = x; // sum has type f returns

但对变量使用decltype时,它会保留高层const及引用,这和auto不同。

const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x is const int
decltype(cj) = x; // y is const int&
decltype(cj) z; // error: z is a reference, must be initialized.

如果我们将decltype应用到表达式,结果可能是个引用:

一般来说,如果该表达式产生的结果能放在赋值语句的左边,那么decltype返回的就是个引用

int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // addition yileds a int; b is int.
decltype(*p) c; // error: c is int&, must be initialized.

正如我们看到的,*p返回的对象可以放到赋值语句的左边,它就是个引用。

autodecltype另一重要的区别是: decltype进行解析类型是取决于表达式的形式。举个例子:加上括号的变量应用decltype就是个 引用。因为,如果加上括号,编译器认为它是个表达式,而它又能放在赋值语句的左边。

decltype((i)) d; // error: d is int&,  must be initialized
decltype(i) e; // ok; e is int