C++11中auto的使用

本文详细介绍了C++11中auto关键字的功能与用法,包括类型推导、变量声明与初始化的要求,并通过示例代码展示了auto在不同场景下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在C语言中,就有了auto关键字,它被当作是一个变量的存储类型修饰符,表示自动变量(局部变量)。它不能被单独使用,否则编译器会给出警告。在C++11标准中,添加了新的类型推导特性。在C ++11中,使用auto定义的变量不能使用其它类型修饰符修饰,该变量的类型由编译器根据初始化数据自动确定。

C++中类型检查是在编译阶段。动态类型语言能做到在运行时决定类型,主要归功于一技术,这技术是类型推导。在C++11中,可以通过重定义auto关键字来实现类型推导。

         在C++11中,使用auto关键字可以要求编译器对变量的类型进行自动推导。

         auto关键字:类型推导,从该关键字的初始化表达式中推导变量的类型。

         在块作用域、命名空间作用域、for循环的初始化语句内声明变量的时候,变量的类型可以被省略,使用关键字auto来代替。

         auto声明的变量必须被初始化,以使编译器能够从其初始化表达式中推导出其类型。

         声明为auto的变量在编译时期就分配了内存,而不是到了运行时期,所以使用auto不再引发任何速度延迟,这也意味着使用auto的时候,这个变量不初始化会报错,因为编译器无法知道这个变量的类型。

         auto使用时需注意:

         (1)、可以使用const、volatile、pointer(*)、reference(&)、rvalue reference(&&)等说明符和声明符来修饰auto关键字;

         (2)、用auto声明的变量必须初始化;

         (3)、auto不能与其它任何类型说明符一起使用;

         (4)、方法、参数或模板参数不能被声明为auto;

         (5)、定义在堆上的变量,使用了auto的表达式必须被初始化;

         (6)、auto是一个占位符,不是类型,不能用于类型转换或其它一些操作,如sizeof、typeid;

         (7)、auto关键字内声明的声明符列表的所有符号必须解析为同一类型;

         (8)、auto不能自动推导成CV-qualifiers(constant& volatile qualifiers),除非被声明为引用类型;     

         (9)、auto会退化成指向数组的指针,除非被声明为引用;

         (10)、auto不能作为函数的返回类型,在C++14中是可以的。

         建议:大多数情况使用关键字auto,除非非常需要转换。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "auto.hpp"
#include <iostream>
#include <cmath>
#include <typeinfo>
#include <string>
#include <map>
#include <list>
#include <deque>
#include <vector>

//////////////////////////////////////////////////
// reference: http://en.cppreference.com/w/cpp/language/auto
template<class T, class U>
auto add(T t, U u) -> decltype(t + u) // the return type is the type of operator+(T, U)
{
	return t + u;
}

auto get_fun(int arg) -> double(*)(double) // same as: double (*get_fun(int))(double)
{
	switch (arg) {
		case 1: return std::fabs;
		case 2: return std::sin;
		default: return std::cos;
	}
}

int test_auto1()
{
	auto a = 1 + 2;
	std::cout << "type of a: " << typeid(a).name() << '\n'; // type of a: int
	auto b = add(1, 1.2);
	std::cout << "type of b: " << typeid(b).name() << '\n'; // type of b: double
	auto c = { 1, 2 };
	std::cout << "type of c: " << typeid(c).name() << '\n'; // type of c: class std::initializer_list<int>

	auto my_lambda = [](int x) { return x + 3; };
	std::cout << "my_lambda: " << my_lambda(5) << '\n'; // my_lambda: 8

	auto my_fun = get_fun(2);
	std::cout << "type of my_fun: " << typeid(my_fun).name() << '\n'; // type of my_fun: double (__cdecl*)(double)
	std::cout << "my_fun: " << my_fun(3) << '\n'; // my_fun: 0.14112

	// auto int x; // error as of C++11: "auto" is no longer a storage-class specifier // error C3530: “auto”不能与任何其他类型说明符组合

	return 0;
}

////////////////////////////////////////////
// reference: https://msdn.microsoft.com/zh-cn/library/dd293667(v=vs.120).aspx
int f(int x) { return x; }

int test_auto2()
{
	int count = 10;
	int& countRef = count;
	auto myAuto = countRef;

	countRef = 11;
	std::cout << count << " " << std::endl; // 11

	myAuto = 12;
	std::cout << count << std::endl; // 11

	// 1. 下面的声明等效。 在第一个语句中,声明 j 变量为类型 int。 在第二个语句,因为初始化表达式 (0) 是整数,所以变量 k 推导为 int 类型
	int j = 0;  // Variable j is explicitly type int.
	auto k = 0; // Variable k is implicitly type int because 0 is an integer.

	// 2. 以下声明等效,但第二个声明比第一个简单
	std::map<int, std::list<std::string>> m;
	std::map<int, std::list<std::string>>::iterator i = m.begin();
	auto i_ = m.begin();

	// 3. 声明 iter 和 elem 变量类型
	std::deque<double> dqDoubleData(10, 0.1);

	for (auto iter = dqDoubleData.begin(); iter != dqDoubleData.end(); ++iter) { /* ... */}

	// prefer range-for loops with the following information in mind
	// (this applies to any range-for with auto, not just deque)

	for (auto elem : dqDoubleData) // COPIES elements, not much better than the previous examples 
	{ /* ... */ }

	for (auto& elem : dqDoubleData) // observes and/or modifies elements IN-PLACE
	{ /* ... */ }

	for (const auto& elem : dqDoubleData) // observes elements IN-PLACE
	{ /* ... */ }

	// 4. 使用 new 运算符
	double x = 12.34;
	auto *y = new auto(x), **z = new auto(&x);

	// 5. 所有符号解析为同一类型
	auto x_ = 1, *y_ = &x_, **z_ = &y_; // Resolves to int.
	auto a(2.01), *b(&a);         // Resolves to double.
	auto c = 'a', *d(&c);          // Resolves to char.
	auto m_ = 1, &n_ = m_;            // Resolves to int.

	// 6. 使用条件运算符 (?:)
	int v1 = 100, v2 = 200;
	auto e = v1 > v2 ? v1 : v2;

	// 7. 将变量 x7 初始化类型 int,将引用的变量 y7 初始化为类型 const int,及将变量 fp 初始化为指向返回类型 int 的函数的指针
	auto x7 = f(0);
	const auto & y7 = f(1);
	int(*p)(int x7);
	p = f;
	auto fp = p;

	return 0;
}

/////////////////////////////////////
// reference: http://www.learncpp.com/cpp-tutorial/4-8-the-auto-keyword/
int add_3(int x, int y)
{
	return x + y;
}

int test_auto3()
{
	auto d = 5.0; // 5.0 is a double literal, so d will be type double
	auto i = 1 + 2; // 1 + 2 evaluates to an integer, so i will be type int

	auto sum = add_3(5, 6); // add_3() returns an int, so sum will be type int

	return 0;
}

GitHubhttps://github.com/fengbingchun/Messy_Test

<think>嗯,用户想了解C++auto使用。好的,首先我得回忆一下auto关键字的用途和演变。记得在C++11之前,auto是用来声明自动存储期的,但基本上没人用,因为局部变量默认就是自动的。C++11之后,auto被重新定义为类型推导工具,这是个重要的特性。 那用户可能想知道auto的基本用法,比如变量声明时的类型推导。比如auto x = 42;这样x会被推导为int。然后可能需要举几个例子,比如处理复杂类型时的方便之处,比如迭代器或者lambda表达式。 接下来,用户可能想了解auto使用场景。例如在模板编程中,当类型名称很长或者复杂时,auto可以简化代码。比如容器迭代器,用auto代替std::vector<int>::iterator,这样代码更简洁。另外,范围for循环中使用auto&来遍历容器元素,避免不必要的拷贝。 还要注意auto的推导规则。比如auto会去除引用和const限定符,如果需要保留这些,可能需要结合decltype或者使用auto&、const auto等。例如,const auto&可以保持常量和引用属性。 另外,用户可能想知道auto的限制。比如不能用于函数参数(虽然C++20允许在部分情况下使用),或者无法推导数组类型。还有,当初始化表达式有歧义时,auto可能会导致意料之外的类型推导,需要特别注意。 可能还需要提到auto在返回类型推导中的应用,C++14允许函数返回类型使用auto,但需要保证所有返回语句的类型一致。还有结构化绑定,C++17中可以用auto来解包元组或结构体成员,比如auto [a, b] = std::make_pair(1, 2); 在解释的时候要结构清晰,分点说明,每个部分用例子来辅助理解。同时要注意用户可能的疑问点,比如什么时候该用auto,什么时候不该用,以及潜在的问题。比如过度使用auto可能导致代码可读性下降,特别是当类型不明确时,需要权衡。 可能还要比较一下auto和显式类型声明的优缺点,强调auto在提高代码可维护性和减少重复冗长类型名称方面的优势。同时提醒用户注意在需要明确类型信息的时候,显式声明可能更合适。 最后,总结一下auto的最佳实践,比如在类型明显或复杂时使用,避免在简单类型如int的情况下滥用,保持代码的可读性。这样用户就能全面了解auto使用方法和注意事项了。</think>在C++中,`auto` 是一个用于自动类型推导的关键字。以下是其核心用法的分步解析: --- ### 一、基本用法 1. **变量声明** `auto` 可根据初始化表达式自动推导变量类型: ```cpp auto x = 5; // x 推导为 int auto str = "hello"; // str 推导为 const char* ``` 2. **复杂类型简化** 避免冗长的类型声明,尤其在模板和容器场景中: ```cpp std::vector<std::pair<int, std::string>> vec; auto it = vec.begin(); // 等价于 std::vector<std::pair<int, std::string>>::iterator ``` --- ### 二、关键使用场景 1. **范围for循环** 遍历容器时结合引用/常量引用: ```cpp std::vector<int> nums{1, 2, 3}; for (auto& num : nums) { // 避免拷贝,允许修改元素 num *= 2; } for (const auto& num : nums) { // 只读访问 std::cout << num << " "; } ``` 2. **Lambda表达式** 存储lambda或简化函数对象: ```cpp auto add = [](int a, int b) { return a + b; }; std::cout << add(3, 4); // 输出7 ``` 3. **函数返回类型推导(C++14+)** 需保证所有返回路径类型一致: ```cpp auto multiply(int a, int b) { return a * b; // 返回类型推导为int } ``` --- ### 三、推导规则与注意事项 1. **引用和常量性** `auto` 默认会丢弃引用和顶层const: ```cpp const int a = 10; auto b = a; // b 是int(const被丢弃) auto& c = a; // c 是const int&(需显式声明引用) ``` 2. **万能引用(C++11+)** 结合 `auto&&` 实现完美转发: ```cpp template <typename T> void log(T&& param) { auto&& val = std::forward<T>(param); // 保留参数类型(左值/右值) } ``` 3. **结构化绑定(C++17+)** 解包复合类型成员: ```cpp std::pair<int, std::string> p{42, "answer"}; auto [num, str] = p; // num是int,str是std::string ``` --- ### 四、限制与最佳实践 1. **禁止使用的情况** - 函数参数类型(C++20前) - 非静态成员变量(需显式类型) - 数组类型推导(如 `auto arr = {1, 2};` 推导为 `std::initializer_list<int>`) 2. **可读性权衡** - 优先在类型复杂或明确的场景使用(如迭代器、lambda) - 避免过度使用导致类型信息丢失(例如 `auto result = getData();` 若 `getData()` 类型不明确时) --- ### 五、总结 `auto` 的主要优势在于简化代码、减少冗余和提高泛型代码的灵活性。合理使用时需平衡类型明确性与代码简洁性,重点关注以下场景: $$ \text{适用场景} \subseteq \{\text{复杂类型}, \text{模板}, \text{lambda}, \text{范围循环}\} $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值