高效c++之auto推导

123 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情

auto基本用法

在 C++11 之前的版本(C++98 和 C++ 03)中,定义变量或者声明变量之前都必须指明它的类型,比如 int、char 等;但是在一些比较灵活的语言中,程序员在定义变量时可以不指明具体的类型,而是让编译器(或者解释器)自己去推导,这就让代码的编写更加方便。

C++11 为了顺应这种趋势也开始支持自动类型推导了!C++11 使用 auto 关键字来支持自动类型推导。

auto 关键字基本的使用语法如下:

auto name = value;

name 是变量的名字,value 是变量的初始值。

注意:auto 仅仅是一个占位符,在编译器期间它会被真正的类型所替代。或者说,C++ 中的变量必须是有明确类型的,只是这个类型是由编译器自己推导出来的。

auto 类型推导的简单例子:

auto n = 10; //int
auto f = 12.8; //double
auto p = &n; //int*
auto url = "http://c.biancheng.net/cplus/";//const char*

auto 高级用法

auto 除了可以独立使用,还可以和某些具体类型混合使用,这样 auto 表示的就是“半个”类型,而不是完整的类型。

int  x = 0;
auto *p1 = &x;   //p1 为 int *,auto 推导为 int
auto  p2 = &x;   //p2 为 int*,auto 推导为 int*
auto &r1  = x;   //r1 为 int&,auto 推导为 int
auto r2 = r1;    //r2 为  int,auto 推导为 int
​
auto x = 27;
const auto cx = x;
const auto& rx = x;
auto&& uref1 = x;//int&
auto&& uref2 = cx;//const int&
auto&& uref3 = 27;//int&&

std::initializer_list

C++11中引入了统一初始化列表,相对应的则是std::initializer_list模板类型。

auto  x1 = {1,2,3}; //此时x1被推导为std::initializer_list<T>
auto  x1 = {1,2,3.0}; //error, 始化列表是模板类型,因此所有的元素必须是同一类型,否则会初始化失败auto x = {11,23,9}
template<typename T>
void f(T param);
f(x);   //编译错误,无法进行推导。template<typename T>
void f(std::initializer_list<T> param);
f(x);   //编译错误,无法进行推导。

auto用于推导函数的返回类型,auto是不能推导初始化列表的。

auto createInitList() {     //C++14支持这种写法,C++11中需要结合decltype
    return { 1,2 ,3 };
}

不能作为lambda的参数,注意是lambda的参数,普通函数的参数是可以的,C++11中不支持lambda的参数使用auto,C++14开始支持。

auto lda = [](const auto& v) {};
lda({1,2,3});   //编译出错,无法推导初始化列表。

数组

const char name[] = "test";
auto arr1 = name;       //arr1的类型是const char*类型
auto& arr2 = name;      //arr2的类型是const char(&)[5]

函数

void someFunc(int,doubel);
auto func1 = someFunc;  //void(*)(int,double)
auto& func2 = someFunc; //void(&)(int,double)

auto 的应用

使用 auto 定义迭代器

auto 的一个典型应用场景是用来定义 stl 的迭代器。

vector< vector<int> > v;
vector< vector<int> >::iterator i = v.begin();
auto i = v.begin();  //使用 auto 代替具体的类型

auto 用于泛型编程

auto 的另一个应用就是当我们不知道变量是什么类型,或者不希望指明具体类型的时候,比如泛型编程中。

#include <iostream>
using namespace std;
class A{
public:
    static int get(void){
        return 100;
    }
};
class B{
public:
    static const char* get(void){
        return "http://c.biancheng.net/cplus/";
    }
};

不用auto

template <typename T1, typename T2>  //额外增加一个模板参数 T2
void func(void){
    T2 val = T1::get();
    cout << val << endl;
}
int main(void){
    //调用时也要手动给模板参数赋值
    func<A, int>();
    func<B, const char*>();
    return 0;
}

用auto

template <typename T>
void func(void){
    auto val = T::get();
    cout << val << endl;
}
int main(void){
    func<A>();
    func<B>();
    return 0;
}

auto的限制

auto 不能在函数的参数中使用

f(auto x); //error

auto 不能作用于类的非静态成员变量(也就是没有 static 关键字修饰的成员变量)中。

auto 关键字不能定义数组,比如下面的例子就是错误的:

auto  str[] = url;  //arr 为数组,所以不能使用 auto

auto 不能作用于模板参数

template <typename T>
class A{
};
int  main(){
    A<int> C1;
    A<auto> C2 = C1;  //错误
    return 0;
}