C++11的类型推导详解 - auto & decltype
auto & decltype
C++11引入了auto和decltype关键字,使用他们可以在编译期就推导出变量或者表达式的类型,方便开发者编码也简化了代码。
auto
auto 是 C++11 引入的关键字,用于自动推导变量的类型。通过使用 auto,编译器可以根据变量初始化表达式的类型来确定变量的类型,从而简化了代码编写,并提高了代码的可读性和灵活性。
使用 auto 可以减少代码中重复书写类型的情况,特别是对于模板编程、迭代器和lambda表达式等场景,可以显著减少代码量。
以下是 auto 的一些常见用法和示例:
-
自动推导基本类型:
auto x = 10; // x的类型为int auto y = 3.14; // y的类型为double auto z = "Hello"; // z的类型为const char*
-
自动推导表达式的类型:
int a = 5, b = 10; auto result = a + b; // result的类型为int
-
结合迭代器进行自动推导:
std::vector<int> vec = {1, 2, 3, 4, 5}; for (auto it = vec.begin(); it != vec.end(); ++it) { // ... }
-
自动推导lambda表达式的返回类型:
auto add = [](int x, int y) { return x + y; }; // add的类型为lambda表达式返回类型,即int
使用 auto 可以使代码更加简洁清晰,尤其在模板编程中,可以大大减少代码的重复性和冗长性。但要注意,在某些情况下过度使用 auto 可能会降低代码的可读性,因此需要适度使用,根据具体情况权衡使用 auto 的利弊。
总结一下auto的限制:
-
auto的使用必须马上初始化,否则无法推导出类型
-
auto在一行定义多个变量时,各个变量的推导不能产生二义性,否则编译失败
-
auto不能用作函数参数
-
在类中auto不能用作非静态成员变量
-
auto不能定义数组,可以定义指针
-
auto无法推导出模板参数
再看这段代码:
int i = 0;
auto *a = &i; // a是int*
auto &b = i; // b是int&
auto c = b; // c是int,忽略了引用
const auto d = i; // d是const int
auto e = d; // e是int
const auto& f = e; // f是const int&
auto &g = f; // g是const int&
首先下文中的 cv
是指 const 和volatile
在不声明为引用或指针时,auto会忽略等号右边的引用类型和cv
限定
在声明为引用或者指针时,auto会保留等号右边的引用和cv
属性
什么时候使用auto?
这里没有绝对答案,只能说一下我自己的理解,个人认为在不影响代码代码可读性的前提下尽可能使用auto是蛮好的,复杂类型就使用auto,int、double这种就没有必要使用auto了吧,看下面这段代码:
auto func = [&] {
cout << "xxx";
}; // 对于func你难道不使用auto吗,反正我是不关心lambda表达式究竟是什么类型。
auto asyncfunc = std::async(std::launch::async, func);
// 对于asyncfunc你难道不使用auto吗,我是懒得写std::futurexxx等代码,而且我也记不住它返回的究竟是什么...
decltype
decltype 是 C++11 引入的一个关键字,用于获取表达式的类型。它的作用是在编译期间推导出表达式的类型,并返回该类型。decltype 可以用于任何表达式,包括变量、函数调用、类成员访问等。
使用 decltype 可以帮助程序员编写更加通用、灵活的代码,特别是在模板编程和泛型编程中。它能够保证某些操作的类型与其参数的类型相匹配,从而提高了代码的类型安全性。
以下是 decltype 的一些常见用法和示例:
-
获取变量的类型:
int x = 10; decltype(x) y; // y的类型为int
-
获取表达式的类型:
int x = 10; decltype(x + 5) y; // y的类型为int,因为x + 5的结果为int
-
获取函数返回值的类型:
int foo(); decltype(foo()) result; // result的类型为foo()函数的返回类型
-
获取类成员的类型:
class MyClass { public: int x; }; MyClass obj; decltype(obj.x) y; // y的类型为int,因为obj.x的类型为int
总的来说,decltype 提供了一种强大的方法来在编译期间获取表达式的类型,使得代码更具通用性和可维护性。
auto和decltype的配合使用
auto和decltype一般配合使用在推导函数返回值的类型问题上。
下面这段代码
template<typename T, typename U>
return_value add(T t, U u) { // t和v类型不确定,无法推导出return_value类型
return t + u;
}
上面代码由于t和u类型不确定,那如何推导出返回值类型呢,我们可能会想到这种
template<typename T, typename U>
decltype(t + u) add(T t, U u) { // t和u尚未定义
return t + u;
}
这段代码在C++11上是编译不过的,因为在decltype(t +u)推导时,t和u尚未定义,就会编译出错,所以有了下面的叫做返回类型后置的配合使用方法:
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
返回值后置类型语法就是为了解决函数返回制类型依赖于参数但却难以确定返回值类型的问题。