在C++11中,auto 关键字被引入用于自动类型推断。它允许编译器根据初始化表达式自动推断变量的类型,从而简化代码并提高可读性。以下是一些关于 auto 的复习要点:
1. 基本用法
auto 关键字用于声明变量时,编译器会根据初始化表达式的类型自动推断变量的类型。
auto x = 42; // x 的类型被推断为 int
auto y = 3.14; // y 的类型被推断为 double
auto z = "Hello"; // z 的类型被推断为 const char*
auto nb; // error,变量必须要初始化
auto double nbl; // 语法错误, 不能修改数据类型
当变量不是指针或者引用类型时,推导的结果中不会保留const、volatile关键字
当变量是指针或者引用类型时,推导的结果中会保留const、volatile关键字
int temp = 110;
auto *a = &temp;
auto b = &temp;
auto &c = temp;
auto d = temp;
//变量a的数据类型为 int*,因此auto关键字被推导为 int类型
//变量b的数据类型为 int*,因此auto关键字被推导为 int*类型
//变量c的数据类型为 int&,因此auto关键字被推导为 int类型
//变量d的数据类型为 int,因此auto关键字被推导为 int类型
2. 与复杂类型一起使用
auto 在处理复杂类型时特别有用,尤其是在模板编程和迭代器中。
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); ++it) {
// it 的类型被推断为 std::vector<int>::iterator
std::cout << *it << std::endl;
}
3. 与 const 和引用一起使用
auto 可以与 const 和引用结合使用,但需要注意推断规则。
const auto a = 10; // a 的类型被推断为 const int
auto& b = a; // b 的类型被推断为 const int&
auto c = b; // c 的类型被推断为 int(去掉了 const 和引用)
int tmp = 250;
const auto a1 = tmp;
auto a2 = a1;
const auto &a3 = tmp;
auto &a4 = a3;
//变量a1的数据类型为 const int,因此auto关键字被推导为 int类型
//变量a2的数据类型为 int,但是a2没有声明为指针或引用因此 const属性被去掉, auto被推导为 int
//变量a3的数据类型为 const int&,a3被声明为引用因此 const属性被保留,auto关键字被推导为 int类型
//变量a4的数据类型为 const int&,a4被声明为引用因此 const属性被保留,auto关键字被推导为 const int类型
4. auto 与函数返回类型
C++14 引入了 auto 作为函数返回类型的推断,但在 C++11 中,auto 只能用于尾随返回类型。
// C++11
auto add(int a, int b) -> int {
return a + b;
}
// C++14
auto add(int a, int b) {
return a + b;
}
5. auto 与 decltype
decltype 可以与 auto 一起使用,用于推断表达式的类型。
int x = 10;
decltype(x) y = 20; // y 的类型被推断为 int
6. auto 的限制
-
auto不能用于函数参数(C++20 引入了auto作为函数参数类型)。 -
auto不能用于非静态成员变量。 -
auto不能用于数组类型。
auto关键字并不是万能的,在以下这些场景中是不能完成类型推导的:
- 不能作为函数参数使用。因为只有在函数调用的时候才会给函数参数传递实参,auto要求必须要给修饰的变量赋值,因此二者矛盾。
int func(auto a, auto b) // error
{
cout << "a: " << a <<", b: " << b << endl;
}
- 不能用于类的非静态成员变量的初始化
class Test
{
auto v1 = 0; // error
static auto v2 = 0; // error,类的静态非常量成员不允许在类内部直接初始化
static const auto v3 = 10; // ok
}
- 不能使用auto关键字定义数组
int func()
{
int array[] = {1,2,3,4,5}; // 定义数组
auto t1 = array; // ok, t1被推导为 int* 类型
auto t2[] = array; // error, auto无法定义数组
auto t3[] = {1,2,3,4,5};; // error, auto无法定义数组
}
- 无法使用auto推导出模板参数
template <typename T>
struct Test{}
int func()
{
Test<double> t;
Test<auto> t1 = t; // error, 无法推导出模板类型
return 0;
}
7. auto 与初始化列表
auto 与初始化列表一起使用时,推断的类型是 std::initializer_list。
auto list = {1, 2, 3}; // list 的类型被推断为 std::initializer_list<int>
8. auto 与 lambda 表达式
auto 可以用于存储 lambda 表达式。
auto lambda = [](int x) { return x * x; };
int result = lambda(5); // result 的值为 25
9. auto 与模板
auto 在模板编程中非常有用,可以简化代码并减少模板参数的使用。
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
#include <iostream>
#include <string>
using namespace std;
class T1
{
public:
static int get()
{
return 10;
}
};
class T2
{
public:
static string get()
{
return "hello, world";
}
};
template <class A>
void func(void)
{
auto val = A::get();
cout << "val: " << val << endl;
}
int main()
{
func<T1>();
func<T2>();
return 0;
}
在这个例子中定义了泛型函数func,在函数中调用了类A的静态方法 get() ,这个函数的返回值是不能确定的,如果不使用auto,就需要再定义一个模板参数,并且在外部调用时手动指定get的返回值类型,具体代码如下:
#include <iostream>
#include <string>
using namespace std;
class T1
{
public:
static int get()
{
return 0;
}
};
class T2
{
public:
static string get()
{
return "hello, world";
}
};
template <class A, typename B> // 添加了模板参数 B
void func(void)
{
B val = A::get();
cout << "val: " << val << endl;
}
int main()
{
func<T1, int>(); // 手动指定返回值类型 -> int
func<T2, string>(); // 手动指定返回值类型 -> string
return 0;
}
10. auto 与范围 for 循环
auto 常用于范围 for 循环中,简化迭代代码。
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto& elem : vec) {
elem *= 2; // elem 的类型被推断为 int&
}
总结
auto 是 C++11 引入的一个强大特性,它简化了代码并提高了可读性,特别是在处理复杂类型和模板编程时。然而,使用时需要注意类型推断的规则,以避免潜在的错误。
1474

被折叠的 条评论
为什么被折叠?



