2.3 类型推导
在传统C++中,参数的类型必须明确定义,这会很大程度上降低我们的变成速度。尤其是当我们面对一大堆复杂的模板类型时,必须明确指定变量的类型才能继续进行后续的编码。不仅降低开发速度,代码也变得又臭又长
auto
auto 在很早以前就进入C++了,咱们也不去纠结以前到底干什么用,咱就说说现在有什么用。
使用 auto 进行类型推导的一个最为常见的例子就是迭代器。
//在 C++11 之前
for (vector<int>::iterator itr = vec.begin(); itr != vec.end(); ++itr)
//使用 auto
for (auto itr = vec.begin(); itr != vec.end(); ++itr)
//一些常见的用法
auto i = 5; //i 被推导为 int
auto arr = new auto(10); //arr 被推导为 int *
从C++20起,auto 可以被用作函数传参,如下代码:
int add(auto x, auto y)
{
return x + y;
}
auto i = 5; //i 被推导为 int
auto j = 6; //j 被推导为 int
cout << add(i, j) << endl;
注意:auto 还不能用于数组类型的推导,如下代码:
auto auto_arr2[10] = { arr }; //错误,无法推导数组类型
decltype(表达式)
有时候,我们可能需要计算某个表达式的类型,如下代码:
auto x = 1;
auto y = 2;
decltype(x + y) z;
配合 std::is_same<T, U> 可以判断 T 和 U 两个类型是否相等,如下代码:
if (is_same<decltype(x), int>::value)
cout << "type x == int" << endl; //可以正常输出
if (is_same<decltype(x), float>::value)
cout << "type x == float" << endl; //不能输出
尾返回类型推导
在传统C++中,如下代码:
template<typename R, typename T, typename U>
R add(T x, U y)
{
return x + y;
}
注意;typename 和 class 在模板参数列表中没有区别,在 typename 这个关键字出现之前,都是使用 class 来定义模板参数的。但在模板中定义有嵌套依赖类型的变量时,需要用 typename 消除歧义。
上面的代码不但丑,而且又很大问题。这个问题是,在调用 add() 函数的时候,我们并不知道他会做些什么,以及会获得一个什么样的返回类型。
其实,这里在传统 C++ 中也可以得到解决,那就是指定参数类型,如下代码:
cout << add<int, int, int>(1, 2) << endl;
在C++11中,你可能会想到使用 decltype 推导 x + y 的类型,如下代码:
decltype(x + y) add(T x, U y)
但是,还是不行,因为在编译期读到 decltype(x + y) 的时候,x 和 y未被定义,无法推导类型。
为了解决上面的那个问题,C++引入了一个叫尾返回类型,利用 atuo 关键字将返回类型后置:
template<typename T, typename U>
auto add2(T x, U y) -> decltype(x + y)
{
return x + y;
}
上面的代码看起来怪怪的,而且 -> 符号在 C++ 中有其他意义,个人感觉不是非常友好。还好从 C++14 开始,可以直接让普通函数具备返回值类型推导,因此,可以出现下面的写法:
template<typename T, typename U>
auto add3(T x, U y)
{
return x + y;
}
decltype(auto)
decltype(auto) 是C++14开始提供的一个比较复杂的用法。这个用法涉及到参数转发的概念,这里先略过,等到说到参数转发的时候补充。
类型推导小结
1.类型推导的使用,在保证效率和可读性的前提下适当使用,不要滥用。
2.能够使用类型推导的前提是,你需要提供足够的信息,让编译器可以利用这些信息进行类型推导