std::function用法学习

转自:https://blog.csdn.net/wangshubo1989/article/details/49134235

 1.介绍

std::function是一个函数对象类,可以接受并存储任何符合其签名的可调用对象,它包装其它任意的函数对象,被包装的函数对象具有类型为T1, …,TN的N个参数,并且返回一个可转换到R类型的值。声明格式是这样:

std::function<R(T1,T2,...TN))> func;

使用 模板转换构造函数接收被包装的函数对象。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、函数指针、std::bind、以及其它函数对象等。std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(我们知道像函数指针这类可调用实体,是类型不安全的)。

std::function来实现回调函数,在函数形参中代替函数指针,更安全也更可视化。

2.例子

#include <iostream>
#include <functional>

std::function< int(int)> Functional; // 声明一个function对象,返回为int类型,接受一个int类型的参数

// 普通函数
int TestFunc(int a)
{
    return a;
}

// Lambda表达式
auto lambda = [](int a)->int{ return a; };

// 仿函数(functor)
class Functor
{
public:
    int operator()(int a)
    {
        return a;
    }
};

// 1.类成员函数
// 2.类静态函数
class TestClass
{
public:
    int ClassMember(int a) { return a; }
    static int StaticMember(int a) { return a; }
};

int main() { 

    // 普通函数
    Functional = TestFunc;  // 直接通过函数名,即函数指针赋值即可。std::function 内部会存储一个指向 TestFunc 的指针
    int result = Functional(10);// 可以直接调用
    cout << "普通函数:"<< result << endl;

    // Lambda表达式
    Functional = lambda;
    result = Functional(20);
    cout << "Lambda表达式:"<< result << endl;

    // 仿函数。仿函数是一个重载了函数调用运算符 operator() 的类,它使得类的对象能够像函数一样被调用。
    Functor testFunctor;
    Functional = testFunctor;
    result = Functional(30);
    cout << "仿函数:"<< result << endl;

    // 类成员函数,需要先bind到具体的类
    TestClass testObj;
    Functional = std::bind(&TestClass::ClassMember, testObj, std::placeholders::_1);// _1表示占位符,调用时传参
    result = Functional(40);
    cout << "类成员函数:"<< result << endl;

    // 类静态函数,可以认为是普通函数了
    Functional = TestClass::StaticMember;
    result = Functional(50);
    cout << "类静态函数:"<< result << endl;

    cout<<endl;
    return 0;
}

 3.原型

template< class R, class... Args >
class function<R(Args...)>

构造函数,转自chatgpt:

#include <iostream>
#include <memory>

template<typename>
class Function; // Primary template declaration

template<typename R, typename... Args> // 模板参数
class Function<R(Args...)> {
public:
    // Default constructor
    Function() : callable(nullptr) {}

    // Constructor from a function pointer
    // 内部可调用指针指向初始化的函数
    template<typename F>
    Function(F f) : callable(std::make_unique<CallableModel<F>>(f)) {}

    // Copy constructor
    Function(const Function& other)
        : callable(other.callable ? other.callable->clone() : nullptr) {}

    // Move constructor
    Function(Function&& other) noexcept = default;

    // Copy assignment operator
    Function& operator=(const Function& other) {
        if (this != &other) {
            callable = other.callable ? other.callable->clone() : nullptr;
        }
        return *this;
    }

    // Move assignment operator
    Function& operator=(Function&& other) noexcept = default;

    // Call operator。重载operator(),仿函数了。
    R operator()(Args... args) const {
        if (!callable) {
            throw std::bad_function_call();
        }
        // 直接把参数转发给可调用对象了。
        return callable->invoke(std::forward<Args>(args)...);
    }

    // Check if the function object is callable
    explicit operator bool() const noexcept {
        return static_cast<bool>(callable);
    }

private:
    // Base class for type erasure
    struct CallableBase {
        virtual ~CallableBase() = default;
        virtual R invoke(Args...) const = 0;
        virtual std::unique_ptr<CallableBase> clone() const = 0;
    };

    // Derived template class for specific callable types
    template<typename F>
    struct CallableModel : CallableBase {
        F f;

        CallableModel(F f) : f(std::move(f)) {}

        R invoke(Args... args) const override {
            return f(std::forward<Args>(args)...);
        }

        std::unique_ptr<CallableBase> clone() const override {
            return std::make_unique<CallableModel<F>>(f);
        }
    };

    std::unique_ptr<CallableBase> callable; // 用智能指针管理的一个可调用对象
};
View Code

4.兼容性 

void Bar(int a) { cout<<"Bar "<<a<<"\n"; }// 一个int类型的形参
int main() { 
    // bind绑定参数时是根据所绑定的函数Bar来的
    std::function<void(int,int,int)> f =std::bind(Bar,std::placeholders::_1);
    // f可兼容bind返回的function对象,但调用的时候要根据自己的类型实际传参。神奇
    f(5,6,7);
}
// 运行结果:
Bar 5

 同样利用bind和function的兼容性:

double func_double1(int a, int b) {
  return 0.0;
}

double func_int1(int a) {
  return 0;
}

using GetDouble = std::function<double(int, int)>;

std::unordered_map<std::string, GetDouble> double_factory = {
    {"func_double1", func_double1},
    {"func_int1", std::bind(func_int1, std::placeholders::_1)}// 可以通过bind转换一下类型使其兼容,
    // func_int1在实际调用时还是只会使用到一个参数,但func_int1对应的GetDouble调用时是要传入2个的,不过第二个会被忽略掉。神奇的用法啊!
};

  

posted @ 2024-05-09 01:23  lypbendlf  阅读(817)  评论(0编辑  收藏  举报