(点击上方公众号,可快速关注)
类型推导(Type inference 或 Type deduction),顾名思义就是编译器能自动推导出数据类型,免去了显式的类型声明。Java、C#等静态语言都支持该特性,C++也在C++11标准开始支持。
注:在C++中,一般将类型推导称为Type deduction,其他语言不少称之为Type inference,虽然名字不太一样,但指的是一回事。
类型推导与模板也能结合使用,比较复杂且不常用,这里仅介绍最常用的用法。
语法
C++11并没有专门引入新的关键字,重载了现有的auto
关键字,用来告知编译器要类型推导。语法很简单:
[const] [volatile] auto[&|&&] v = expr;
其中,cv和引用都是可选的。编译器根据expr
的推导结果决定变量v
的类型。
用途
最基本也最常用的用法是减少类型名的长度。由于C++引入了类、命名空间等作用域,要限定其中某个类型可能需要多个作用域符号,导致类型名比较长,不利于编码。一般用auto
解决这类情况。
比如,你要声明某个容器类型的迭代器,需要敲这么多字符
std::vector<int> exam;
std::vector<int>::const_iterator it = exam.cbegin();
可以简化为:
auto it = exam.cbegin();
特别说明:C++里的类型推导都是在编译阶段进行的,不影响生成的可执行文件的效率。
注意点
C++里的类型推导能力有限,只能根据初始化值的类型推断对应变量的类型
std::vector<int> exam;
auto it; // error,编译器没法知道it的类型,因为没有初始化的值作为推导的依据
it = exam.cbegin();
int64_t add(int64_t lhs, int64_t rhs);
auto i = 5; // i为int类型,因为整型字面量值默认int类型
auto j = 6; // 同上
auto k = add(i, j); // i和j自动提升为int64_t类型,k为int64_t类型
从上能看出来,C++里的类型推导相对简单,只能根据右边的初始化值的类型推导左边的变量的类型,如果没有右边的表达式没法推导左边的变量类型。这区别于某些编程语言,如Haskell,能根据变量的使用方式推导出变量的类型。还拿上例来说,相应的Haskell代码:
add :: Int64 -> Int64 -> Int64;
let i = 5 -- i为Int64类型,因为字面值5是多态的,
-- 由于在add中作为Int64类型使用,推导出i为Int64类型
let j = 6 -- 同上
let k = add(i, j); -- k为Int64类型
auto推导出的结果是decayed,即
会把右边的
const
或volatile
限定符丢掉会将引用类型转为被引用的类型,即,推导出的变量不是引用类型
同时还会将原始数组以及函数转为相应的指针类型
要多加注意第二点,因为涉及到复制操作,可能影响效率。
std::vector<int> vLarge; //很大的容器 auto vLarge1 = vLarge; // 复制一份给vLarge1 auto& vLarge1 = vLarge; // vLarge1为引用类型
在语法一节里只说了一种初始化方式:
=
,C++有4种初始化方式,非常复杂,有些情况可能比较意外,如下例:
auto i {10}; //等价于于auto i = 10;
auto j = {10}; //j为std::initializer_list<int>
这个时候可使用typeid
获取类型。C++不一致的规则非常多,不用熟记这么多脑裂的规则。
喜欢我的文章,请关注我的公众号。转载请标明出处。