类型推导
PART3:原有语法的实用性增强
特性1:类型推导auto
和decltype
auto
关键字

1、背景
在以前的C++中,auto
关键字用于指明变量的存储类型,和static
关键字是相对的。auto
表明变量是自动存储的,这也是编译器的默认规则,因此写不写系统都会自动加上。例如int a=10;// auto int a=10;表示a自动存储
而在C++11后为了顺应c# JAVAScript PHP
等语言的自动推导变量的特性对auto
重新赋予新的含义。
2、使用方法
auto
关键字的基本使用语法包含有定义一个变量、连续定义多个变量。案例如下:
案例1:定义一个变量
1 | // 案例一:定义一个变量 |
案例2:连续定义多个变量
1 | // 案例二:连续定义多个变量 |
注意:在连续定义多个变量时不能存在二义性。
auto
关键字的高级使用语法包含有混合类型推导、与const
关键字配合使用。案例如下:
案例1:混合类型推导
auto
除了单独使用还可以与某些具体类型混合使用,因此auto
充当半个类型。
1 | int x = 0; |
第五行需要特别==注意==,当auto推导出=
右边为引用类型时,auto
会自动丢弃引用,直接推导出原始类型。
案例2:与const
关键字配合使用
1 | int x = 0; |
第3行中n
为const int
类型,但是被推导为int
类型,这说明等号==右边为const
属性时==,auto
不会使用const
类型,而是==直接推导出non-const
类型==。
第5行中的r2
为const int&
,auto
推导为cosnt int
,这说明当==const
和引用结合时==,auto
的推导将==保留表达式的const
类型==。
对于auto
和const
总结如下:
- 类型不为引用时,
auto
推导结果将不保留表达式的const
属性。 - 当类型为引用时,
auto
推导结果将保留表达式的cosnt
属性。
3、使用限制
1)auto
使用时必须初始化。
2)auto
不能作为函数的参数(因为函数在定义时只是指明了参数的类型,而值是在调用时才会赋值,auto
需要根据值推导类型,在定义时就需要赋值这和函数参数的使用矛盾)。
3)不能定义数组,例如下面的案例就是错误的
1 | char url[] = "http://c.biancheng.net/"; |
4)auto
不能作为模版参数
1 | template <typename T> |
4、应用场景
1)STL
定义迭代器:在使用STL
容器时,需要定义迭代器来遍历容器中的元素,不同的迭代器有不同的类型,在定义迭代器时必须指明,因此可以使用auto
简写。案例如下:
1 | vector<vector<int>> v; |
2)泛型编程:在不知道什么类型或者不希望指定类型时使用。案例如下:
1 | class T1 |
如果没有auto
关键字时应该使用如下方法:
1 | class T1 |
decltype
关键字
1、背景
decltype
的全称是declare type
的缩写,表示“声明类型”。decltype
也是C++11中新增的一个关键字,和auto
的功能一样,主要原因是因为auto
在有些特殊情况下使用不方便甚至无法使用。
2、使用方法
推导的形式如下所示:需要根据exp
来推导变量的类型。而exp
是一个普通的表达式,也可以是任意复杂的形式,但必须保证exp
的结果是有类型的,不能是void
的,例如当exp
调用一个返回类型为void
的函数时,exp
的结果也是void
类型,此时会导致编译错误。
1 | decltype(exp) varname; // decltype主要是根据exp来推导变量的类型。 |
decltype
的推导规则包含以下三条:
exp
是一个不被()
包围的表达式,或者是一个类成员访问表达式,或者是一个单独的变量,则decltype(exp)
的类型和exp
一样。- 若
exp
为一个函数调用,则decltype(exp)
的类型和函数返回值的类型一致。 - 若
exp
是一个左值,或者被括号()
包围,那么decltype(exp)
的类型就是exp
的引用;假设exp
的类型为T
,那么decltype(exp)
的类型就是T&
。
案例1:exp
是一个普通表达式
1 |
|
案例2:exp
为函数调用
1 | //函数声明 |
案例3:exp
为左值,或被()
包围
1 | using namespace std; |
注意:decltype(n = n + m) d = c;
其中n
代表一个左值所以会采用int&
型。
左值:在表达式执行结束后依然存在的数据,右值:表达式执行结束不存在的,是一个临时的。
3、实际应用
1)auto
只能用于类的静态成员,不能用于类的非静态成员(普通成员),因此如果想要推导类的非静态成员必须使用decltype
。
2)解决泛型编程中不能推导const
类型迭代器的问题
1 |
|
在使用decltype
之后
1 |
|
总结
1、使用方法:auto
的推导规则为:auto valueType=value;
根据value
推导出valuetype
。decltype(exp) valueType;
是根据exp
推导出类型和=右边无关。
2、对CV(const、Volatile)关键字的处理:如果表达式不是指针或引用,auto
会自动丢弃const
或volatile
属性。如果是指针或引用则保留cosnt
或volatile
属性。而decltype
会保留const
和volatile
属性。
3、对引用的处理:当表达式为引用时,auto
会丢弃引用类型,直接推导出原始类型;decltype
会保存引用类型。