23.auto 类型推导的原理-灵析社区

菜鸟码转

auto 是 C++ 语言的关键字。C++11 规定,auto 关键字用于两种情况:

  • 声明变量时根据初始化表达式自动推断该变量的类型;
  • 声明函数时函数返回值的占位符;

auto 声明变量时,根据初始化的表达式来推导该变量的类型,此时变量必须进行初始化。使用 auto 类型可以使变量定义变得更为简单,程序结构更为清晰一些,比如以下程序示例:

C++

std::vector<int> vect; 
for(auto it = vect.begin(); it != vect.end(); ++it)
{  //it的类型是std::vector<int>::iterator
    std::cin >> *it;
}
auto ptr = [](double x){return x*x;};//类型为std::function<double(double)>函数对象

使用 auto 关键字做类型自动推导时,依次施加以下规则:

  • 首先,如果初始化表达式是引用,首先去除引用,如果 auto 类型关键字带上 & 则不进行去除;

以下程序程序示例中可以看到 myAuto 是一个 int,而不是引用 int。

C++

#include <iostream>

using namespace std;

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

    countRef = 11;
    cout << count << " ";

    myAuto = 12;
    cout << count << endl;
}
// 11
// 11
  • 其次,去掉剩下的初始化表达式顶层的 const 或 volatile 限定符。
  • C++ 14 以后如果用 {} 来进行赋值,此时 auto 类型推导出的类型为 std::initializer_list;而模板函数的形参推导时不认为这种值列表是一个类型,此时则不能推导出 std::initializer_list 类型。

C++

#include <initializer_list>
int main()
{
    // A 的类型: std::initializer_list<int>
    auto A = { 1, 2 };
    // B 的类型: std::initializer_list<int>
    auto B = { 3 };
    // C 的类型: int
    auto C{ 4 };
    return 0;
}
  • auto 关键字的类型完美转发:

C++11 使用 auto 声明变量时,如:auto&& var=initValue;,则此时 “auto&&” 并不意味着这一定是右值引用类型的变量,而是类似于模板函数参数的类型推导,既可能是左值引用,也可能是右值引用。其目的是把初始化表达式的值分类情况,完美转发给由 auto 声明的变量。也即:

如果初始化值是类型 A 的左值,则声明的变量类型为左值引用 A&;

如果初始化值是类型 A 的右值,则声明的变量类型为右值引用 A&&。

C++


#include<iostream>  
#include <vector>
#include <typeinfo>
using namespace std;
 
struct Widget{};
Widget makeWidget(){ return Widget(); } // 类工厂函数

int main()
{
	Widget&& var1 = Widget(); // var1的类型是右值引用,但是作为左值
	auto&& var2 = var1;       //var2的类型是左值引用
	std::vector<int> v = { 1, 2, 3 };
	auto&& val = v[0]; // std::vector::operator[]的返回值是元素左值,所以val的类型是左值引用
	Widget&& var3 = makeWidget(); // var3是左值,但它的类型是右值引用 
	Widget var4 = static_cast<Widget&&>(var1); // var4是左值,但它的类型是右值引用

	std::cout << typeid(var1).name() << std::endl;
	std::cout << typeid(var2).name() << std::endl;
	std::cout << typeid(val).name() << std::endl;
	std::cout << typeid(var3).name()  << std::endl;
	std::cout << typeid(var4).name() << std::endl;
}


阅读量:2010

点赞量:0

收藏量:0