C++之std::function与std::bind

一、std::function

1、概念

 std::function是一个函数包装器模板,最早来自boost库,对应其boost::function函数包装器。在c++11中,将boost::function纳入标准库中。该函数包装器模板能包装任何类型的可调用元素(callable element),例如普通函数和函数对象。包装器对象可以进行拷贝,并且包装器类型仅仅只依赖于其调用特征(call signature),而不依赖于可调用元素自身的类型。

  • std::function 是一个可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行。
  • 定义格式:std::function<函数类型>。
  • std::function可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数指针更加的灵活和便利。

 

2、包装不同函数

①、包装普通函数

复制代码
#include <iostream>
#include <functional>
using namespace std;

int g_Minus(int i, int j)
{
    return i - j;
}

int main()
{
    function<int(int, int)> f = g_Minus;
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码

②、包装模板函数

复制代码
#include <iostream>
#include <functional>
using namespace std;

template <class T>
T g_Minus(T i, T j)
{
    return i - j;
}

int main()
{
    function<int(int, int)> f = g_Minus<int>;
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码

③、包装lambda表达式

复制代码
#include <iostream>
#include <functional>
using namespace std;

auto g_Minus = [](int i, int j){ return i - j; };

int main()
{
    function<int(int, int)> f = g_Minus;
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码

赋值给函数对象

 

std::function<bool()> fIsItemValid = [this](){
    int timeOutCount = VALUE_0;
    do {
        if(m_parent && m_xAxis && m_yAxis){
            return true;
        }
        else{
            ++timeOutCount;
            QThread::msleep(TIME_OUT_MS);
            if(timeOutCount >= TIME_OUT_COUNT) return false;
            continue;
        }
    } while(true);
};
auto getItemState = [this](std::function<bool()> f){
    std::future<bool> t = std::async(f);
    if(t.get()) emit this->sgl_createItem();
    else qCritical()<<"time out!! item is null."<<m_parent<<m_xAxis<<m_yAxis;
};
std::thread t(getItemState, fIsItemValid);
t.detach();

 

直接等于函数对象

 

 

④、包装函数对象

       非模板类型:

复制代码
#include <iostream>
#include <functional>
using namespace std;

struct Minus
{
    int operator() (int i, int j)
    {
        return i - j;
    }
};

int main()
{
    function<int(int, int)> f = Minus();
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码

       模板类型:

复制代码
#include <iostream>
#include <functional>
using namespace std;

template <class T>
struct Minus
{
    T operator() (T i, T j)
    {
        return i - j;
    }
};

int main()
{
    function<int(int, int)> f = Minus<int>();
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码

⑤、包装类静态成员函数

       非模板类型:

复制代码
#include <iostream>
#include <functional>
using namespace std;

class Math
{
public:
    static int Minus(int i, int j)
    {
        return i - j;
    }
};

int main()
{
    function<int(int, int)> f = &Math::Minus;
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码

       模板类型:

复制代码
#include <iostream>
#include <functional>
using namespace std;

class Math
{
public:
    template <class T>
    static T Minus(T i, T j)
    {
        return i - j;
    }
};

int main()
{
    function<int(int, int)> f = &Math::Minus<int>;
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码

⑥、包装类对象成员函数

       非模板类型:

复制代码
#include <iostream>
#include <functional>
using namespace std;

class Math
{
public:
    int Minus(int i, int j)
    {
        return i - j;
    }
};

int main()
{
    Math m;
    function<int(int, int)> f = bind(&Math::Minus, &m, placeholders::_1, placeholders::_2);
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码
//class Mos : public QObject
std::unique_ptr<Mos>  pMos =
        std::make_unique<Mos>(new Mos());
auto p = pMos.get();
std::function<void*(const char*)> f =
        std::bind(&Mos::qt_metacast, p, placeholders::_1);
qDebug()<<p;            //Mos(0x9fe2f0)
qDebug()<<f("QObject"); //0x9fe2f0
qDebug()<<f("Mos");     //0x9fe2f0
qDebug()<<f("1");       //0x0

 

      

 

模板类型:

复制代码
#include <iostream>
#include <functional>
using namespace std;

class Math
{
public:
    template <class T>
    T Minus(T i, T j)
    {
        return i - j;
    }
};

int main()
{
    Math m;
    function<int(int, int)> f = bind(&Math::Minus<int>, &m, placeholders::_1, placeholders::_2);
    cout << f(1, 2) << endl;                                            // -1
    return 1;
}
复制代码

转载:https://www.cnblogs.com/heartchord/p/5017071.html

 

3、应用1:传递一个std::function给对象,对象内部的定时器每秒执行一次此函数

class Handle {
public:
    Handle(std::function<void()> cb)
        : mCallBack(cb)
    {
        QObject::connect(&timer, &QTimer::timeout, mCallBack);
        timer.start(1000);
    }
private:
    std::function<void()> mCallBack;
    QTimer timer;
};

int main(int argc, char *argv[]){
    QApplication a(argc, argv);
    auto cb {
        [](){
            std::cout<< "timer out..."<<std::endl;
        }
    };
    Handle h(cb);
    return a.exec();
}

首先得到了拉姆达函数,然后通过构造函数传递给Handle对象,传递时执行了拉姆达到std::function的构造转换,然后通过Qt信号槽连接这个std::function对象,实现每秒执行一次function。

 

二、std::bind

1、概念

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

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

链接:https://www.jianshu.com/p/f191e88dcc80
 
概括:设置可调用对象(函数)的某些参数为可变变量,将某些参数设置为固定值,然后将整个调用对象返回成std::funciton类型
 
2、举例
#include <random>
#include <iostream>
#include <memory>
#include <functional>
 
void f(int n1, int n2, int n3, const int& n4, int n5)
{
    std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
 
int g(int n1)
{
    return n1;
}
 
struct Foo {
    void print_sum(int n1, int n2)
    {
        std::cout << n1+n2 << '\n';
    }
    int data = 10;
};
 
int main()
{
    using namespace std::placeholders;  // for _1, _2, _3...
 
    std::cout << "demonstrates argument reordering and pass-by-reference:\n";
    int n = 7;
    // (_1 and _2 are from std::placeholders, and represent future
    // arguments that will be passed to f1)
    auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);
    n = 10;
    f1(1, 2, 1001); // 1 is bound by _1, 2 is bound by _2, 1001 is unused
                    // makes a call to f(2, 42, 1, n, 7)
 
    std::cout << "achieving the same effect using a lambda:\n";
    auto lambda = [ncref=std::cref(n), n=n](auto a, auto b, auto /*unused*/) {
        f(b, 42, a, ncref, n);
    };
    lambda(1, 2, 1001); // same as a call to f1(1, 2, 1001)
 
    std::cout << "nested bind subexpressions share the placeholders:\n";
    auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
    f2(10, 11, 12); // makes a call to f(12, g(12), 12, 4, 5);
 
    std::cout << "common use case: binding a RNG with a distribution:\n";
    std::default_random_engine e;
    std::uniform_int_distribution<> d(0, 10);
    auto rnd = std::bind(d, e); // a copy of e is stored in rnd
    for(int n=0; n<10; ++n)
        std::cout << rnd() << ' ';
    std::cout << '\n';
 
    std::cout << "bind to a pointer to member function:\n";
    Foo foo;
    auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
    f3(5);
 
    std::cout << "bind to a pointer to data member:\n";
    auto f4 = std::bind(&Foo::data, _1);
    std::cout << f4(foo) << '\n';
 
    std::cout << "use smart pointers to call members of the referenced objects:\n";
    std::cout << f4(std::make_shared<Foo>(foo)) << ' '
              << f4(std::make_unique<Foo>(foo)) << '\n';
}

 

posted @ 2021-06-23 17:33  朱小勇  阅读(541)  评论(0编辑  收藏  举报