auto类型推导
在c++11之后, 我们可以通过auto关键字来定义一个变量,使我们可以免于显式地声明其类型,让编译器在编译时自动推导该变量的类型。如果你已经读过了 Effective Modern C++ Item1 模板类型推导详解 ,那么,除了一种特殊的情况外(初始化列表std::initializer_list
),其实你已经知晓了关于auto类型推导的全部内容,因为auto类型推导实际上就是模板类型推导。
模板类型推导的形式如下:
//声明
template<typename T>
void f(ParamType param)
//调用
f(expr);
当进行auto类型推导时,有:
// example1
auto x = expr;
// example2
auto& x = expr;
// example3
auto&& x = expr;
在上述示例中,auto相当于模板中的T,不同的是ParamType:
- example1中,ParamType为T,则x的类型推导规则遵循Item1中的Case3的情况。
- example2中,ParamType为T&,则x的类型推导规则遵循Item1中Case1的情况。
- exmaple3中,ParamType为T&&,则x的类型推导规则遵循Item1中Case2的情况。
auto类型推导实例:
#include <iostream>
#include <memory>
#include <vector>
#include <typeinfo>
int main()
{
std::cout << std::boolalpha;
//auto的推导:
int x = 1;
auto y = x; //y的类型被推导为int,验证如下:
std::cout << "y的类型是int:" << std::is_same<decltype(y), int>::value << std::endl;
std::unique_ptr<int> ptr(new int{1}); //unique_ptr不允许拷贝构造(copy),只允许转移构造(move)
//auto ptr0 = uni_ptr; //copy构造,编译不通过
auto uni_ptr = std::move(ptr); //move构造,成功运行,uni_ptr为右值引用,验证如下:
std::cout << "uni_ptr是右值引用:" << std::is_rvalue_reference<decltype(uni_ptr)>::value << std::endl;
//同时,uni_ptr是左值,因为该变量有名称/可以对其取地址,因此我们可以建立它的左值引用:
std::unique_ptr<int>& ptr_lr = uni_ptr; //ptr_lr为左值引用
///
//auto&的推导:
auto& ptr_a1 = uni_ptr; //ptr_al 为左值引用,验证如下:
std::cout << "ptr_a1是左值引用:" << std::is_lvalue_reference<decltype(ptr_a1)>::value << std::endl;
///
//auto&&的推导:
auto&& ptr_a2 = uni_ptr; //ptr_a2 也为左值引用,验证如下:
std::cout << "ptr_a2是左值引用:" << std::is_lvalue_reference<decltype(ptr_a2)>::value << std::endl;
std::vector< std::unique_ptr<char>> vec;
auto a = std::make_unique<char>('a');
auto b = std::make_unique<char>('b');
auto c = std::make_unique<char>('c');
vec.push_back(std::move(a));
vec.push_back(std::move(b));
vec.push_back(std::move(c));
//这里的elem被推导为左值引用
for (auto& elem : vec)
std::cout << *elem << " ";
puts("");
//这里的elem也被推导为左值引用
for (auto&& elem : vec)
std::cout << *elem << " ";
puts("");
system("pause");
return 0;
}
总结:
从上面的实例可以看出
* 当我们把一个对象(obj)的类型声明为auto&时,我们只能使用一个左值对obj进行初始化,obj的类型一定为左值引用。
* 当我们把一个对象(obj)的类型声明为auto&&时:我们既可以使用左值对obj进行初始化,此时obj的类型为左值引用;也可以使用右值对obj进行初始化,此时obj的类型为右值引用。