部分文章内容为公开资料查询整理,原文出处可能未标注,如有侵权,请联系我,谢谢。邮箱地址:gnivor@163.com ►►►需要气球么?请点击我吧!

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.

 

#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;
}
View Code

 

#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
*/
View Code

 

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 typeis 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可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数指针更加的灵活和便利。
//不同类型可能具有相同的调用形式,如:
// 普通函数
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();
View Code

 

std::bind

可将std::bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。

std::bind将可调用对象与其参数一起进行绑定,绑定后的结果可以使用std::function保存。std::bind主要有以下两个作用:

  • 将可调用对象和其参数绑定成一个防函数;
  • 只绑定部分参数,减少可调用对象传入的参数。

绑定普通函数:

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;
*/
View Code

绑定成员函数:

/*
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
}
View Code

 

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)在使用时,是对参数直接拷贝,而不是引用。

#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;
}
View Code

 

std::result_of

https://zh.cppreference.com/w/cpp/types/result_of

它可以在编译的时候推导出一个函数表达式的返回值类型

#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 中调用不可调用重载
}
View Code

 

posted @ 2019-02-22 14:47  流了个火  阅读(409)  评论(0编辑  收藏  举报
►►►需要气球么?请点击我吧!►►►
View My Stats