《Effective Modern C++》读书笔记(4) -- 尽量使用auto来显式类型声明

来源:互联网 发布:mysql 查看表 编辑:程序博客网 时间:2024/05/21 07:59

写了三篇,发现还是有点啰嗦了,所以下面的笔记改的更为简洁些,更多的是记载自己对这本书的理解和运用。

这节包括的内容有:

  • auto
  • std::function

前言

在C或者C++这类语言中,声明变量的使用通常需要类型声明。例如:

int a = 10;         // 声明一个整形变量a,其值为10

然而有时候我们通常只声明,不定义。例如:

int a;          // 声明一个整形变量a

但是通常这样,有一个小小的问题。如果我忘了对a进行初始化,那么a的值将是未定义的。它可能为被初始化0,具体的还得依赖编译器。这也就是这一节要将的问题。

auto声明

前面写的auto类型推导中讲到过,auto声明的变量必须定义,例如下面这种用法就是不允许的。

int a;              // ok!auto b;             // error!auto c = 10;        // ok!

对于c变量,它被推断为一个整形变量。当然从上面的例子看不出auto的强大之处。我们重新举个栗子,假如我们要声明一个函数,它的作用是进行大小的比较,代码如下:

auto derefUPLess =        [](const std::unique_ptr<Widget>& p1,           const std::unique_ptr<Widget>& p2){ return *p1 < *p2; };

调用很简单,例如:

derefUPLess(p1, p2)

现在我们来推导下,如果不用auto,那么derefUPLess的类型是什么,首先根据闭包,我们知道这是一个函数,且该函数带有两个参数,参数类型都是

const std::unique_ptr<Widget>&

又根据return语句知道,返回类型是bool,综上,我们知道derefUPLess的类型是

// std::function的用法在下面std::function<bool(const std::unique_ptr<Widget>&,                                const std::unique_ptr<Widget>&)>

使用auto极大地省略了代码量。甚至在C++14中还可以使用

// C++14auto derefUPLess =        [](const auto& p1,           const auto& p2){ return *p1 < *p2; };

std::function的用法

std::functionC++11添加的新特性。它是一个模板函数,用来初始化为一个函数指针。与普通的函数指针不同,函数指针只能指向一个函数,而std::function对象能引用任何可调用的对象。

使用也很简单:

std::function<Type(parameter)> func;

例如上面的代码:

std::function<bool(const std::unique_ptr<Widget>&,                                const std::unique_ptr<Widget>&)> derefUPLess;

使用auto而不使用std::function的理由(也是autostd::function的不同之处)

  1. autostd::function对于闭包的内存需求不一样,std::function使用的更多
  2. autostd::function更快

其他注意事项

  1. 在32位Windows操作系统,unsigned是32位的,在64位Windows操作系统,unsigned是64位的。这时候,auto能确保你不犯错。
    例如:
std::vector<int> v;... auto sz = v.size();             // std::vector<int>::size_type is unsigned. sz's type is std::vector<int>::size_type

代码

#include <iostream>#include <functional>#include <memory>class Widget{public:    explicit Widget(int value)        : value_(value)    {        // empty    }    bool operator<(const Widget& t)    {        return value_ < t.value_;    }private:    int value_;};int main(int argc, char const *argv[]){    std::unique_ptr<Widget> p1(std::make_unique<Widget>(1));    std::unique_ptr<Widget> p2(std::make_unique<Widget>(2));    auto derefUPLess =        [](const std::unique_ptr<Widget>& p1,           const std::unique_ptr<Widget>& p2)    { return *p1 < *p2; };    if (derefUPLess(p1, p2)) {        std::cout << "Yes" << std::endl;    }    else {        std::cout << "No" << std::endl;    }    return 0;}

补充

function类似一个容器,可以容纳任意有operator()的类型(函数指针,函数对象,lambda表达式),它是运行时的,可以任意拷贝,赋值,存储其他可调用物。而auto仅是在编译期推导出的一个静态类型变量,它很难再赋以其他值,也无法容纳其他的类型,不能用于泛型编程。

当需要存储一个可调用物用于回调的时候,最好使用function,它具有更多的灵活性,特别是把回调作为类的一个成员的时候我们只能使用function

auto也有它的优点,它的类型是在编译期推到出来的,没有运行时的开销,效率上要比function略高一点。但它声明的变量不能存储其他类型的可调用物,不具有灵活性,只能用于有限范围的延后回调。

阅读全文
0 0