写了三篇,发现还是有点啰嗦了,所以下面的笔记改的更为简洁些,更多的是记载自己对这本书的理解和运用。
这节包括的内容有:
- 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++14
auto derefUPLess =
[](const auto& p1,
const auto& p2)
{ return *p1 < *p2; };
std::function的用法
std::function是C++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的理由(也是auto和std::function的不同之处)
- auto和std::function对于闭包的内存需求不一样,std::function使用的更多
- auto比std::function更快
其他注意事项
- 在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略高一点。但它声明的变量不能存储其他类型的可调用物,不具有灵活性,只能用于有限范围的延后回调。