本节将介绍更多的处理类型的方法。
类型别名
类型别名(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
返回的对象可以放到赋值语句的左边,它就是个引用。
auto
和decltype
另一重要的区别是:
decltype
进行解析类型是取决于表达式的形式。举个例子:加上括号的变量应用decltype就是个
引用。因为,如果加上括号,编译器认为它是个表达式,而它又能放在赋值语句的左边。
decltype((i)) d; // error: d is int&, must be initialized
decltype(i) e; // ok; e is int