C++点滴--auto
2018-01-10 18:27
441 查看
1. 类型推导规则
1.1 auto
auto a = {expression};
如果{expression}是一个引用,则引用修饰符(&)被忽略;
如果{expression}有top-level的const/volatile修饰符,则const/volatile被忽略;
例子:
int i = 0; const int & cri = x; auto a = cri; // type of a is "int", because the reference and the const are ignored; int x = 42; const int* p1 = &x; auto p2 = p1; // const is not ignored, because it's not at top-level; *p2 = 43; // error: p2 is const int*
总结:
去引用;
const能去则去(需要保证const变量不能被修改);
1.2 auto &
auto& ra = {expression};
引用修饰符(&)不能被忽略;
const修饰符也不能被忽略(因为引用保留了,若忽略const,则常量表达式能被修改了);
例子:
const int c = 0; auto& rc = c; //type of rc is "const int &", const is not ignored; otherwise, c can be modified; rc = 1; //error;
总结:
保留引用;
const不能去(需要保证const变量不能被修改);
1.3 auto &&
auto&& rra = {expression};
如果{expression}是左值,则需要添加左值引用&,所以rra的类型变成T& &&,衰减(collapse)成T&;
如果{expression}是右值,则rra的类型是T&&;
例子:
int i = 42; auto&& ri_1 = i; //type of ri_1 is "int& &&", collapsing to "int &"; auto&& ri_2 = 42; //type of ri_2 is "int &&";
总结:
左值,左值引用;
右值,右值引用;
const能去则去(需要保证const变量不能被修改);
2. 使用场景
2.1 基础用法
std::vector<int> vect; // ... for(std::vector<int>::iterator it = vect.begin(); it != vect.end(); ++it) { std::cin >> *it; }
可以更简便的写作:
std::vector<int> vect; // ... for(auto it = vect.begin(); it != vect.end(); ++it) { std::cin >> *it; }
变量it和vect.begin()的类型是完全一样的,因此,编译器可以推断出它的类型,不必麻烦程序员每次重写一遍。还有其他类似的使用方式,其目的是让编译器来推断类型,程序员省去一些打字的工作(毕竟,写个auto是很快捷的)。
然而,本人不喜欢这样的用法,理由是(本人的拙见,欢迎持不同意见的同学来讨论):
打字在编程中占的工作量有限,在这方面节省一点时间,能提高多少效率呢?
程序员在写代码的时候,实际上是很清楚每个变量的类型的,这个时候为了节省一点打字工作而简单的写个auto,维护(阅读)代码的人可能需要自己去推导变量的类型。而这个推导成本,应该远远大于打字节省的工作量吧!
即使对于上面的例子(for循环遍历vector),明确的写出vector< int >::iterator(或者vector< int >::const_iterator),也可以让程序员熟悉vector的使用方式,甚至能够使程序员联想起vector以及iterator的实现(类似的,map及其iterator的实现……)。
所以,本人认为,仅仅为了编码便利,我们不应该使用auto;它应该出现在有正当需求的地方,见下文。
2.2 无法确定类型的地方
比如,我们写这样一个模板函数:template<typename T, typename S> void foo(T lhs, S rhs) { auto prod = lhs * rhs; //... }
C++11以前,表达式lhs*rhs的类型无法确定(若lhs都是int,则为int;若一个int一个double则为double;另外,T和S还可能是程序员自定义的类——重载了乘法运算符——那么结果类型就有无限多可能了),我们该如何写prod的类型呢?
C++11有两种途径来定义prod的类型,其一就是如上所示的auto。另一个是decltype,我在这一篇里介绍。
2.3 Function return type deduction (C++14)
C++11中提供了一个特性:lambda函数的类型可以由return表达式的类型推定。C++14把这一特性扩展到所有函数:也就是,函数的返回类型定义为auto (注意,后面没有 -> decltype(),这是C++11的trailing return type语法)。例如:auto add(int a, int b) { return a + b; }
和2.1节类似,编译器可以根据return语句推断出函数的类型。同样,我不喜欢这样的写法,理由也类似。除此之外,它还有一些限制:
限制1: 若有多个返回语句,则各个返回表达式的类型必须一样;
限制2:可以前置声明,但是定义之前是不能使用的(那前置声明有什么用呢?);
限制3: 返回auto的函数递归时, 递归调用前,至少有一个return 语句。例如:
auto Correct(int i) { if (i == 1) return i; // return type deduced as int else return Correct(i-1)+i; // ok to call it now } auto Wrong(int i) { if (i != 1) return Wrong(i-1)+i; // Too soon to call this. No prior return statement. else return i; // return type deduced as int }
2.4 trailing return type
这是decltype的使用方式,auto只是配合一下。见我的另一篇博客。2.5 Alternate type deduction on declaration
这是auto和decltype结合的使用方式。见我的另一篇博客。相关文章推荐
- 编程经验点滴(三)——《C、C++中指针加 1 的问题》
- C++ auto and decltype Explained
- java与c/c++之间的数据交互-----jni点滴【转】
- C++ auto类型说明符
- C++智能指针auto_ptr的原理及使用
- 【C++深入浅出】智能指针之auto_ptr学习
- C++ 点滴积累(2)
- C/C++:智能指针原理(运算符重载)、使用auto_ptr<A>
- 【C++】智能指针auto_ptr
- 初学C++ 之 auto关键字(IDE:VS2013)
- c++ 模板学习笔记:类模板模拟auto_ptr智能指针(权哥)
- C++ auto_ptr智能指针的用法
- Ubuntu使用点滴(3)-C/C++开发环境配置
- C++ 智能指针Auto_PTR 分析http://www.cnblogs.com/skyofbitbit/p/3649776.html
- C++ 入门教程(七) auto、decltype、常量、类型后缀 和 const
- C++高质量编程点滴
- C++ 深入理解 auto 关键字
- c++的auto_ptr
- C++ 学习笔记(2)变量和基本类型(复合类型:引用、指针)、const、constexpr、typedef(using)、auto、decltype
- 探究c++智能指针中auto_ptr_ref的存在意义