1. 类型推导 auto
decltype
1.1 auto
定义变量的时候,通过初始值推断类型
auto i = 42; // 推断i的类型为int
auto
会忽略顶层const
const int ci = 42;
auto b = ci; // b的类型是int
const auto f = ci; // 可以显式的指明const
auto
和引用
auto &g = ci; // g的推断类型为cont int&
auto
比较有意义的用法是在些一些比较复杂类型时可以方便一点,比如
std::vector<int> ivec = {1, 2, 3, 4, 5};
for (std::vector<int>::const_iterator it = ivec.begin();
it != ivec.end(); ++it) {
std::cout << *it << std::endl;
}
it
迭代器的类型名比较复杂,可以使用 auto
类型推导
for (auto it = ivec.begin(); it != ivec.end(); ++it) {
std::cout << *it << std::endl;
}
// 更简单的遍历,使用范围for
for (auto it : ivec) {
std::cout << it << std::endl;
}
auto
类型推导不是万能的,不应该过度依赖于自动类型推断,它只是使编码更方便,在使用auto
自动类型推断时应该做到“心中有数”。
1.2 decltype
decltype
的功能和 typeof
类似,计算表示式的类型
decltype(表达式)
int i = 42;
auto j = 1;
decltype(i + j) k; // k 的类型是int
decltype(f()) s = x; // s 的类型是函数f() 返回值的类型
decltype
类型计算,它不会执行表达式
decltype
处理顶层 const
和引用的方式与 auto
不同,如果使用的表达式是一个变量,则返回该变量的类型(包括顶层const和引用在内)
const int ci = 0, &cj = ci;
decltype(ci) x = 0; // x的类型是 const int
decltype(cj) y = x; // y的类型是 const int&, y绑定到变量x
decltype(cj) z; // 错误, z是一个引用,必须初始化
decltype
和引用
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // 加法的结果是int,所以b是一个未初始化的int
decltype(*p) c; // 错误,c是 int&, 必须初始化
如果表达式的内容是一个解引用操作,则 decltype
将得到引用类型。
如果表达式是加上了括号的变量,结果将是引用
decltype((i)) d; // d是int&, 必须初始化
decltype(i) e; // e 是 int类型
1.3 尾置类型返回
一个模板函数的代码
template<typename R, typename T, typename U>
R add(T x, U y) {
return x + y;
}
在使用这个模板函数必须指定三个类型参数
int sum = add<int, int, int>(1, 2);
使用尾指类型返回可以简化
template<typename T, typename U>
auto add(T x, U y)-> decltype(x+y) {
return x + y;
}
一个错误的代码
template<typename T, typename U>
decltype(x+y) add(T x, U y) {
return x + y;
}
上面的代码使用 decltype(x+y)
计算返回类型,但是在使用 x
y
之前,编译器并不知它值,根本没法计算类型。