C++ 学习系列 -- std::function 与 std::bind

本文详细介绍了C++11中的std::function和std::bind,包括它们的作用、用法示例,以及如何封装普通函数、函数指针、成员函数、lambda表达式和仿函数对象。std::function作为函数包装器,支持拷贝和移动;std::bind用于绑定函数参数并支持占位符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一  std::function  与 std::bind 的介绍

     1. std::function  

     std::function 是 c++ 11 的新特性 ,包含在头文件<functional>中,为了更方便的调用函数而引入。

       std::function 是一个函数包装器(function wrapper),可以包装任何可调用实体,包括如下几种:

       普通函数、函数指针、成员函数、静态函数、lambda 表达式 与 仿函数对象。

     std::function 对象实例可以拷贝与移动,可以使用指定的调用特征来调用目标元素。当 std::function 对象实例未包含任何实体时,调用该 std::function 对象实例时,会抛出std::bad_function_call异常。

    2. std::bind

      std::bind 是 c++ 11 的新特性,其作用与其字面名称相似,是为了绑定函数的某些参数。

std::bind 是一种延迟计算的思想,将可调用函数对象保存起来,在需要调用时再去调用。可以绑定

仿函数对象、普通函数与成员函数,其参数可以支持占位符。

占位符:

       std::placeholders::_1 是一个占位符,绑定函数的第一个参数,std::placeholders::_2 是一个占位符,绑定函数的第二个参数,std::placeholders::_n 是一个占位符,绑定函数的第 n 个参数。

二   源码 

2.1    std::function

template<typename _Signature>
    class function;

  /**
   *  @brief Primary class template for std::function.
   *  @ingroup functors
   *
   *  Polymorphic function wrapper.
   */
  template<typename _Res, typename... _ArgTypes>
    class function<_Res(_ArgTypes...)>
    : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>,
      private _Function_base
    {
      template<typename _Func,
	       typename _Res2 = typename result_of<_Func&(_ArgTypes...)>::type>
	struct _Callable : __check_func_return_type<_Res2, _Res> { };

      // Used so the return type convertibility checks aren't done when
      // performing overload resolution for copy construction/assignment.
      template<typename _Tp>
	struct _Callable<function, _Tp> : false_type { };

      template<typename _Cond, typename _Tp>
	using _Requires = typename enable_if<_Cond::value, _Tp>::type;

    public:
      typedef _Res result_type;

      // [3.7.2.1] construct/copy/destroy

      /**
       *  @brief Default construct creates an empty function call wrapper.
       *  @post @c !(bool)*this
       */
      function() noexcept
      : _Function_base() { }

      /**
       *  @brief Creates an empty function call wrapper.
       *  @post @c !(bool)*this
       */
      function(nullptr_t) noexcept
      : _Function_base() { }

      /**
       *  @brief %Function copy constructor.
       *  @param __x A %function object with identical call signature.
       *  @post @c bool(*this) == bool(__x)
       *
       *  The newly-created %function contains a copy of the target of @a
       *  __x (if it has one).
       */
      function(const function& __x);

      /**
       *  @brief %Function move constructor.
       *  @param __x A %function object rvalue with identical call signature.
       *
       *  The newly-created %function contains the target of @a __x
       *  (if it has one).
       */
      function(function&& __x) noexcept : _Function_base()
      {
	       __x.swap(*this);
      }

      /**
       *  @brief Builds a %function that targets a copy of the incoming
       *  function object.
       *  @param __f A %function object that is callable with parameters of
       *  type @c T1, @c T2, ..., @c TN and returns a value convertible
       *  to @c Res.
       *
       *  The newly-created %function object will target a copy of
       *  @a __f. If @a __f is @c reference_wrapper<F>, then this function
       *  object will contain a reference to the function object @c
       *  __f.get(). If @a __f is a NULL function pointer or NULL
       *  pointer-to-member, the newly-created object will be empty.
       *
       *  If @a __f is a non-NULL function pointer or an object of type @c
       *  reference_wrapper<F>, this function will not throw.
       */
      template<typename _Functor,
	       typename = _Requires<__not_<is_same<_Functor, function>>, void>,
	       typename = _Requires<_Callable<_Functor>, void>>
	function(_Functor);

      /**
       *  @brief %Function assignment operator.
       *  @param __x A %function with identical call signature.
       *  @post @c (bool)*this == (bool)x
       *  @returns @c *this
       *
       *  The target of @a __x is copied to @c *this. If @a __x has no
       *  target, then @c *this will be empty.
       *
       *  If @a __x targets a function pointer or a reference to a function
       *  object, then this operation will not throw an %exception.
       */
      function&
      operator=(const function& __x)
      {
	    function(__x).swap(*this);
	    return *this;
      }

      /**
       *  @brief %Function move-assignment operator.
       *  @param __x A %function rvalue with identical call signature.
       *  @returns @c *this
       *
       *  The target of @a __x is moved to @c *this. If @a __x has no
       *  target, then @c *this will be empty.
       *
       *  If @a __x targets a function pointer or a reference to a function
       *  object, then this operation will not throw an %exception.
       */
      function&
      operator=(function&& __x) noexcept
      {
	    function(std::move(__x)).swap(*this);
	    return *this;
      }
     
      template<typename _Functor>
	_Requires<_Callable<typename decay<_Functor>::type>, function&>
	operator=(_Functor&& __f)
	{
	  function(std::forward<_Functor>(__f)).swap(*this);
	  return *this;
	}

      /// @overload
      template<typename _Functor>
	function&
	operator=(reference_wrapper<_Functor> __f) noexcept
	{
	  function(__f).swap(*this);
	  return *this;
	}

      /**
       *  @brief Invokes the function targeted by @c *this.
       *  @returns the result of the target.
       *  @throws bad_function_call when @c !(bool)*this
       *
       *  The function call operator invokes the target function object
       *  stored by @c this.
       */
      _Res operator()(_ArgTypes... __args) const;
  };

2.2    std::bind

// Trait type used to remove std::bind() from overload set via SFINAE
  // when first argument has integer type, so that std::bind() will
  // not be a better match than ::bind() from the BSD Sockets API.
  template<typename _Tp, typename _Tp2 = typename decay<_Tp>::type>
    using __is_socketlike = __or_<is_integral<_Tp2>, is_enum<_Tp2>>;

  template<bool _SocketLike, typename _Func, typename... _BoundArgs>
    struct _Bind_helper
    : _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...>
    {
      typedef typename decay<_Func>::type __func_type;
      typedef _Bind<__func_type(typename decay<_BoundArgs>::type...)> type;
    };

  // Partial specialization for is_socketlike == true, does not define
  // nested type so std::bind() will not participate in overload resolution
  // when the first argument might be a socket file descriptor.
  template<typename _Func, typename... _BoundArgs>
    struct _Bind_helper<true, _Func, _BoundArgs...>
    { };

  /**
   *  @brief Function template for std::bind.
   *  @ingroup binders
   */
  template<typename _Func, typename... _BoundArgs>
    inline typename
    _Bind_helper<__is_socketlike<_Func>::value, _Func, _BoundArgs...>::type
    bind(_Func&& __f, _BoundArgs&&... __args)
    {
      typedef _Bind_helper<false, _Func, _BoundArgs...> __helper_type;
      return typename __helper_type::type(std::forward<_Func>(__f),
					  std::forward<_BoundArgs>(__args)...);
    }

  template<typename _Result, typename _Func, typename... _BoundArgs>
    struct _Bindres_helper
    : _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...>
    {
      typedef typename decay<_Func>::type __functor_type;
      typedef _Bind_result<_Result,
			   __functor_type(typename decay<_BoundArgs>::type...)>
	type;
    };

  /**
   *  @brief Function template for std::bind<R>.
   *  @ingroup binders
   */
  template<typename _Result, typename _Func, typename... _BoundArgs>
    inline
    typename _Bindres_helper<_Result, _Func, _BoundArgs...>::type
    bind(_Func&& __f, _BoundArgs&&... __args)
    {
      typedef _Bindres_helper<_Result, _Func, _BoundArgs...> __helper_type;
      return typename __helper_type::type(std::forward<_Func>(__f),
					  std::forward<_BoundArgs>(__args)...);
    }

三   使用例子

 

#include<iostream>
#include<functional>

int (*func_ptr)(int);

int func(int a)
{
    std::cout << "func: " << a << endl;
    return a;
}

void f(int n1, int n2, int n3, const int& n4, int n5) {
    std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << std::endl;
}

template<typename T>
T fun2(T a){
    return a + 2;
}

struct my_add{
    int operator()(int x){
        return x + 9;
    }
};

struct Foo
{
    static void func11()
    {
        std::cout << "static void func1......" << std::endl;
    }
    static void func12(int val)
    {
        std::cout << "static void func1( val "<< val << "......" << std::endl;
    }

    void func2(int val)
    {
        std::cout << "void func2(val "<< val << ")......" << std::endl;
    }

};

int main()
{
     // 1. 包装函数
     std::function<int(int)>  f1 = func;
     f1(66);
     std::cout << sizeof (f1) << std::endl;

     // 2. 包装函数指针
     func_ptr = func;
     func_ptr(88);

     // 3. 包装模板函数
     f1 = fun2<int>;
     f1(688);

     // 4. 包装仿函数
     f1 = my_add();
     std::cout << f1(87) << std::endl;

     // 5. 包装lambda 函数
     auto tmp_func = [](int a)->int
     {
           return a;
     };

     f1 = tmp_func;
     std::cout << f1(8888) << std::endl;


     // 6 包装静态函数
     std::function<void(void)> f61 = Foo::func11;
     f61();

     std::function<void(int)>  f62 = Foo::func12;
     f62(666);


     // 7 包装类成员函数
     Foo foo;
     std::function<void(int)> f7 = std::bind(&Foo::func2, foo, std::placeholders::_1);
     f7(888);


     // bind
     auto f2 = std::bind(f, std::placeholders::_3, std::placeholders::_2, std::placeholders::_1, 4, 5);
     f2(3, 2, 1);
     std::function<void(int, int, int)> ff = f2;
     ff(3, 2, 1);
     std::cout << "------ main end ------" << std::endl;

     return 0;
}

输出:

### C++ 中 `std::function` `std::bind` 的用法及区别 #### 定义基本概念 `std::function` 是一种通用多态函数封装器,可以存储任何可调用对象(如普通函数、lambda 表达式、绑定表达式或其他函数对象)。其灵活性使得它能够作为回调机制的一部分,在事件驱动编程其他场景下非常有用。 ```cpp #include <functional> #include <iostream> void simpleFunction(int a) { std::cout << "Value is: " << a << '\n'; } int main() { // 创建一个 std::function 对象并赋值给简单函数 std::function<void(int)> f = simpleFunction; f(42); } ``` 另一方面,`std::bind` 提供了一种方式来创建新的可调用对象,这些新对象可以通过固定某些参数或将多个可调用实体组合在一起的方式简化现有可调用目标的接口。通过 bind 可以提前设置部分参数,从而减少后续调用时传递相同参数的需求[^1]。 ```cpp #include <functional> #include <iostream> class MyClass { public: void memberFunc(int i, double d) const { std::cout << "Integer value: " << i << ", Double Value:" << d << "\n"; } }; int main(){ using namespace std::placeholders; MyClass obj; // 绑定成员函数到特定实例,并预先设定第一个参数 auto boundMember = std::bind(&MyClass::memberFunc, &obj, _1, 3.14); // 调用已绑定的对象只需要提供剩余未固定的参数即可 boundMember(7); } ``` #### 主要差异点 - **目的不同**: `std::function` 更侧重于作为一个容器去保存各种类型的可调用对象;而 `std::bind` 则专注于调整已有可调用对象的行为模式,比如预设一些输入参数。 - **使用场合的区别**: 当需要定义一个能接受多种不同类型但签名兼容的函数指针的地方时,应该优先考虑使用 `std::function`; 如果想要改变某个具体函数或方法的工作方式,则可以选择 `std::bind`. - **性能考量**: 在大多数情况下,直接使用 lambda 表达式可能比使用 `std::bind` 效率更高,因为后者可能会引入额外的小型分配开销以及间接层。然而对于复杂情况下的参数绑定操作来说,`std::bind` 还是有它的优势所在[^2].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值