C++ | function

C++ | function

引言

程序设计时,经常需要使用回调函数,如果针对每种不同的可调用对象或函数单独进行声明类型,代码会非常冗余

因此C++ 引入了std::function类模板,std::function对象实例可被拷贝,移动等,可以使用指定的调用特征来直接调用目标元素,不依赖于其元素自身的类型

该函数包装器模板能包装任何类型的可调用实体,如普通函数、函数对象、成员函数、静态函数、lamda表达式和函数对象等。

当std::function对象实例未包含任何实际可调用实体时,调用该std::function对象实例将抛出std::bad_function_call异常。

可调用对象(callable object)包括:

  • 函数
  • 函数指针
  • lambda 表达式
  • bind 创建的对象
  • 重载了函数调用运算符的类(仿函数)

实战

1. 模板类声明

简单说,std::function 就是提前存储了函数实体,在需要的时候回调出来即可。其入参和返回值均与被调用函数保持一致。

如果绑定函数实体的时候,还没确定函数参数,可以通过 std::bind 进行函数入参绑定,等到参数确定好,再传入合适的位置以供调用。

  /** _Res 是返回类型, _ArgTypes 是参数类型
   *  @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 = __invoke_result<_Func&, _ArgTypes...>>
	struct _Callable
	: __is_invocable_impl<_Res2, _Res>::type
	{ };

      // 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
      function() noexcept
      : _Function_base() { }

      function(nullptr_t) noexcept
      : _Function_base() { }

      function(const function& __x);

      function(function&& __x) noexcept : _Function_base()
      {
	__x.swap(*this);
      }

   // ======================= Randy 还有诸多成员函数 =======================

  
/** 只能和 nullptr 和 0 比较
   *  @brief Compares a polymorphic function object wrapper against 0
   *  (the NULL pointer). 
   *  @returns @c false if the wrapper has no target, @c true otherwise
   *
   *  This function will not throw an %exception.
   */
  template<typename _Res, typename... _Args>
    inline bool
    operator!=(const function<_Res(_Args...)>& __f, nullptr_t) noexcept
    { return static_cast<bool>(__f); }

  /// @overload
  template<typename _Res, typename... _Args>
    inline bool
    operator!=(nullptr_t, const function<_Res(_Args...)>& __f) noexcept
    { return static_cast<bool>(__f); }
          
          
    private:
      using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...);
      _Invoker_type _M_invoker;
  };

因此,定义一个std::function 的时候,需要将入参及返回值传递给 std::function 模板类即可

std::function<std::string(int)> randy;
std::function<int(char,double)> sesame;

2.普通函数/Lambda表达式/仿函数/类成员函数

#include <iostream>
#include <functional>

// 普通函数
int commonFunc(int lhs, int rhs) {
	return lhs + rhs;
}

// Lambda表达式
auto lamdaFunc = [](int lhs, int rhs) {
	return lhs + rhs;
};

// 函数对象 换成 struct 亦可
class Functor {
public:
	int operator()(int lhs, int rhs) {
		return lhs + rhs;
	}
};


// 类成员函数
class Randy
{
public:
	// 1.类成员函数
	int RandyMemberFunc(int lhs, int rhs) { return lhs + rhs; }
	// 2.类静态成员函数
	static int RandyStaticFunc(int lhs, int rhs) { return lhs + rhs; }
};

int main() {
    // 定义一个 std::function 函数
    std::function<int(int, int)> qcj_CallBack;
    int result = -1;

	// 普通函数
	qcj_CallBack = commonFunc;
	result = qcj_CallBack(2, 1);
	std::cout << "common function: " << result << std::endl;

	// 普通函数指针
	qcj_CallBack = &commonFunc;
	result = qcj_CallBack(2 ,2);
	std::cout << "common function pointer: " << result << std::endl;

	// Lambda表达式
	qcj_CallBack = lamdaFunc;
	result = qcj_CallBack(2, 3);
	std::cout << "lambda function: " << result << std::endl;

	// 函数对象
	Functor functor_randy;
	qcj_CallBack = functor_randy;
	result = qcj_CallBack(2, 4);
	std::cout << "function object: " << result << std::endl;

	// 类成员函数(使用std::bind绑定类成员函数, std::placeholders::_2为占位符,顺序与原函数入参对应,次序可调换)
             // qcj_CallBack = std::bind(&Randy::RandyMemberFunc, randy, std::placeholders::_2, std::placeholders::_1);
            // 上式这么写也可以,调用时 第2个入参在前,第1个入参在后
	Randy randy;
	qcj_CallBack = std::bind(&Randy::RandyMemberFunc, randy, std::placeholders::_1, std::placeholders::_2);
	result = qcj_CallBack(2, 5);
	std::cout << "class member function: " << result << std::endl;

	// 类静态成员函数
	qcj_CallBack = Randy::RandyStaticFunc;
	result = qcj_CallBack(2, 6);
	std::cout << "class static member function: " << result << std::endl;

	return 0;
}

结果:

common function: 3
common function pointer: 4
lambda function: 5
function object:: 6
class member function: 7
class static member function: 8

3.函数指针/模板函数/模板函数对象

#include <iostream>
#include <functional>

// 回调函数
std::function<std::string(std::string)> RandyFuncCallBack;

// 函数指针
std::string (*RandyFuncPtr)(std::string);

template<typename T>
T RandyTemplate(T t_arg){
    return "三戒纪元: " + t_arg;
}

// 模板函数对象
template <typename T>
struct RandyStruct{
    T operator()(T t_arg){
        return "Randy struct: " + t_arg;
    }
};

int main(int argc, char *argv[]){
    //std::function包装模板函数
    RandyFuncCallBack = RandyTemplate<std::string>; 
    std::cout << RandyFuncCallBack("std::function called.") << std::endl; 
    
    // 函数指针
    RandyFuncPtr = RandyTemplate;
    RandyFuncCallBack = RandyFuncPtr;
    std::cout << RandyFuncCallBack("function ptr called.") << std::endl;
    
    // 模板函数对象
     RandyFuncCallBack = RandyStruct<std::string>(); 
    std::cout << RandyFuncCallBack("struct function called.") << std::endl;
    return 0;
}

结果:

三戒纪元: std::function called.
三戒纪元: function ptr called.
Randy struct: struct function called.

4.静态函数/类模板静态函数/模板类成员函数/类成员函数

#include <iostream>
#include <functional>

// 回调函数
std::function<std::string(std::string)> RandyFuncCallBack;

// 类成员函数
struct Randy{
    std::string RandyCommonFunc(std::string sesame){
        return "Randy common function: " + sesame;
    }

    static std::string RandyStaticFunc(std::string t_arg){
        return "Randy static function: " + t_arg;
    }
};

// 模板类
template <typename T>
struct RandyTemplateStruct{
    // 模板对象函数
    T RandyTemplateFunc(T sesame){
        return "Randy Template function: " + sesame;
    }

    // 模板对象静态函数
    static T RandyTemplateStaticFunc(T t_arg){
        return "Randy Template static function: " + t_arg;
    }
};

int main(int argc, char *argv[]){
    Randy randy;

    // 类成员函数
    RandyFuncCallBack = std::bind(&Randy::RandyCommonFunc, &randy, std::placeholders::_1); 
    std::cout << RandyFuncCallBack("RandyCommonFunc called.") << std::endl; 

    // 类成员函数
    RandyFuncCallBack = randy.RandyStaticFunc;
    std::cout << RandyFuncCallBack("RandyStaticFunc called.") << std::endl; 

    // 模板对象函数
    RandyTemplateStruct<std::string> randyTemplate;
    RandyFuncCallBack = std::bind(&RandyTemplateStruct<std::string>::RandyTemplateFunc, &randyTemplate, std::placeholders::_1); 
    std::cout << RandyFuncCallBack("RandyTemplateFunc called.") << std::endl; 

    // 模板对象静态函数
    RandyFuncCallBack = RandyTemplateStruct<std::string>::RandyTemplateStaticFunc;
    std::cout << RandyFuncCallBack("RandyTemplateStaticFunc called.") << std::endl; 
    return 0;
}

结果:

Randy common function: RandyCommonFunc called.
Randy static function: RandyStaticFunc called.
Randy Template function: RandyTemplateFunc called.
Randy Template static function: RandyTemplateStaticFunc called.

5. copy/move

#include <iostream>
#include <functional>

// 回调函数
std::function<std::string(std::string)> RandyFuncCallBack;

std::string PrintRandy(std::string sesame) {
	return ">>>>>>>>>> 三戒纪元: " + sesame + " <<<<<<<<<<";
}


int main(int argc, char *argv[]){
    // 未包装任何对象实体
    std::cout << RandyFuncCallBack("RandyFuncCallBack") << std::endl;
    // 结果为:Aborted (core dumped)
    
    RandyFuncCallBack = PrintRandy;
    std::cout << RandyFuncCallBack("RandyFuncCallBack") << std::endl;

     //拷贝
    std::function<std::string(std::string)> CallBack_Copy(RandyFuncCallBack);
    std::cout << CallBack_Copy("CallBack_Copy") << std::endl;
    
    //拷贝赋值运算符
    std::function<std::string(std::string)> CallBack_CopyAssign = RandyFuncCallBack; 
    std::cout << CallBack_CopyAssign("CallBack_CopyAssign.") << std::endl;

    //移动赋值运算符
    std::function<std::string(std::string)>&& CallBack_MoveAssign = std::move(RandyFuncCallBack); 
    std::cout << CallBack_MoveAssign("CallBack_MoveAssign") << std::endl;
    std::cout << RandyFuncCallBack("RandyFuncCallBack") << std::endl;

    return 0;
}

结果:

>>>>>>>>>> 三戒纪元: RandyFuncCallBack <<<<<<<<<<
>>>>>>>>>> 三戒纪元: CallBack_Copy <<<<<<<<<<
>>>>>>>>>> 三戒纪元: CallBack_CopyAssign. <<<<<<<<<<
>>>>>>>>>> 三戒纪元: CallBack_MoveAssign <<<<<<<<<<
>>>>>>>>>> 三戒纪元: RandyFuncCallBack <<<<<<<<<<

Reference


欢迎关注公众号【三戒纪元】

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值