C++笔记--std::相关
std::packaged_task
https://www.cnblogs.com/haippy/p/3279565.html
https://en.cppreference.com/w/cpp/thread/packaged_task
std::packaged_task 包装一个可调用的对象,并且允许异步获取该可调用对象产生的结果,从包装可调用对象意义上来讲,std::packaged_task 与 std::function 类似,只不过 std::packaged_task 将其包装的可调用对象的执行结果传递给一个 std::future 对象(该对象通常在另外一个线程中获取 std::packaged_task 任务的执行结果)。
std::packaged_task 对象内部包含了两个最基本元素,一、被包装的任务(stored task),任务(task)是一个可调用的对象,如函数指针、成员函数指针或者函数对象,二、共享状态(shared state),用于保存任务的返回值,可以通过 std::future 对象来达到异步访问共享状态的效果。
可以通过 std::packged_task::get_future 来获取与共享状态相关联的 std::future 对象。在调用该函数之后,两个对象共享相同的共享状态,具体解释如下:
- std::packaged_task 对象是异步 Provider,它在某一时刻通过调用被包装的任务来设置共享状态的值。
- std::future 对象是一个异步返回对象,通过它可以获得共享状态的值,当然在必要的时候需要等待共享状态标志变为 ready.
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> // std::cout #include <utility> // std::move #include <future> // std::packaged_task, std::future #include <thread> // std::thread int main () { std::packaged_task<int(int)> foo; // 默认构造函数. // 使用 lambda 表达式初始化一个 packaged_task 对象. std::packaged_task<int(int)> bar([](int x){return x*2;}); foo = std::move(bar); // move-赋值操作,也是 C++11 中的新特性. // 获取与 packaged_task 共享状态相关联的 future 对象. std::future<int> ret = foo.get_future(); std::thread(std::move(foo), 10).detach(); // 产生线程,调用被包装的任务. int value = ret.get(); // 等待任务完成并获取结果. std::cout << "The double of 10 is " << value << ".\n"; return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cmath> #include <thread> #include <future> #include <functional> // unique function to avoid disambiguating the std::pow overload set int f(int x, int y) { return std::pow(x,y); } void task_lambda() { std::packaged_task<int(int,int)> task([](int a, int b) { return std::pow(a, b); }); std::future<int> result = task.get_future(); task(2, 9); std::cout << "task_lambda:\t" << result.get() << '\n'; } void task_bind() { std::packaged_task<int()> task(std::bind(f, 2, 11)); std::future<int> result = task.get_future(); task(); std::cout << "task_bind:\t" << result.get() << '\n'; } void task_thread() { std::packaged_task<int(int,int)> task(f); std::future<int> result = task.get_future(); std::thread task_td(std::move(task), 2, 10); task_td.join(); std::cout << "task_thread:\t" << result.get() << '\n'; } int main() { task_lambda(); task_bind(); task_thread(); } /* 输出结果 task_lambda: 512 task_bind: 2048 task_thread: 1024 */
std::remove_reference
https://en.cppreference.com/w/cpp/types/remove_reference
If the type T
is a reference type, provides the member typedef type
which is the type referred to by T
. Otherwise type
is T
.
std::move和std::forward
不错,可以仔细看看: https://www.jianshu.com/p/b90d1091a4ff
https://www.cnblogs.com/boydfd/p/5182743.html
std::function和std::bind
https://www.jianshu.com/p/f191e88dcc80
https://blog.csdn.net/zzhongcy/article/details/88018204
std::function
- std::function 是一个可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行。
- 定义格式:std::function<函数类型>。
- std::function可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数指针更加的灵活和便利。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//不同类型可能具有相同的调用形式,如: // 普通函数 int add(int a, int b){return a+b;} // lambda表达式 auto mod = [](int a, int b){ return a % b;} // 函数对象类 struct divide{ int operator()(int denominator, int divisor){ return denominator/divisor; } }; //上述三种可调用对象虽然类型不同,但是共享了一种调用形式: int(int ,int) //std::function就可以将上述类型保存起来,如下: std::function<int(int ,int)> a = add; std::function<int(int ,int)> b = mod ; std::function<int(int ,int)> c = divide();
std::bind
可将std::bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。
std::bind将可调用对象与其参数一起进行绑定,绑定后的结果可以使用std::function保存。std::bind主要有以下两个作用:
- 将可调用对象和其参数绑定成一个防函数;
- 只绑定部分参数,减少可调用对象传入的参数。
绑定普通函数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
double my_divide (double x, double y) {return x/y;} auto fn_half = std::bind (my_divide,_1,2); std::cout << fn_half(10) << '\n'; // 5 /* bind的第一个参数是函数名,普通函数做实参时,会隐式转换成函数指针。因此std::bind (my_divide,_1,2)等价于std::bind (&my_divide,_1,2); _1表示占位符,位于<functional>中,std::placeholders::_1; */
绑定成员函数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址。 必须显示的指定&Foo::print_sum,因为编译器不会将对象的成员函数隐式转换成函数指针,所以必须在Foo::print_sum前添加&; 使用对象成员函数的指针时,必须要知道该指针属于哪个对象,因此第二个参数为对象的地址 &foo; */ struct Foo { void print_sum(int n1, int n2) { std::cout << n1+n2 << '\n'; } int data = 10; }; int main() { Foo foo; auto f = std::bind(&Foo::print_sum, &foo, 95, std::placeholders::_1); f(5); // 100 }
std::rec和std::cref
https://blog.csdn.net/lmb1612977696/article/details/81543802
http://www.cnblogs.com/jiayayao/p/6527713.html
C++本身有引用(&),为什么C++11又引入了std::ref?
主要是考虑函数式编程(如std::bind)在使用时,是对参数直接拷贝,而不是引用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <functional> #include <iostream> void f(int& n1, int& n2, const int& n3) { std::cout << "In function: n1[" << n1 << "] n2[" << n2 << "] n3[" << n3 << "]" << std::endl; ++n1; // 增加存储于函数对象的 n1 副本 ++n2; // 增加 main() 的 n2 //++n3; // 编译错误 std::cout << "In function end: n1[" << n1 << "] n2[" << n2 << "] n3[" << n3 << "]" << std::endl; } int main() { int n1 = 1, n2 = 1, n3 = 1; std::cout << "Before function: n1[" << n1 << "] n2[" << n2 << "] n3[" << n3 << "]" << std::endl; std::function<void()> bound_f = std::bind(f, n1, std::ref(n2), std::cref(n3)); bound_f(); std::cout << "After function: n1[" << n1 << "] n2[" << n2 << "] n3[" << n3 << "]" << std::endl; }
std::result_of
https://zh.cppreference.com/w/cpp/types/result_of
它可以在编译的时候推导出一个函数表达式的返回值类型
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <type_traits> #include <iostream> struct S { double operator()(char, int&); float operator()(int) { return 1.0;} }; template<class T> typename std::result_of<T(int)>::type f(T& t) { std::cout << "overload of f for callable T\n"; return t(0); } template<class T, class U> int f(U u) { std::cout << "overload of f for non-callable T\n"; return u; } int main() { // 以 char 和 int 参数调用 S 的结果是 double std::result_of<S(char, int&)>::type d = 3.14; // d 拥有 double 类型 static_assert(std::is_same<decltype(d), double>::value, ""); // 以 int 参数调用 S 的结果是 float std::result_of<S(int)>::type x = 3.14; // x 拥有 float 类型 static_assert(std::is_same<decltype(x), float>::value, ""); // result_of 能以指向成员函数的指针以如下方式使用 struct C { double Func(char, int&); }; std::result_of<decltype(&C::Func)(C, char, int&)>::type g = 3.14; static_assert(std::is_same<decltype(g), double>::value, ""); f<C>(1); // C++11 中可能编译失败; C++14 中调用不可调用重载 }