众所周知function可以封装任意类型的可调用对象功能十分强大这篇文章主要是想讲解一下function的工作原理。可调用对象有这么几种类型仿函数对象、函数指针、lambda表达式... ... 即使这几种可调用对象的参数和返回值类型相同也会被会被判定为不同的类型毕竟仿函数本质上是类而函数指针是一个函数指针类型。我们首先要解决的问题就是如何接收不同的类型答案是模板class function { public: templateclass T function(T t) { _t t; } }那么问题又来了function类不知道T这个类型如何提前定义一个对象_t去存储传参进来的可调用对象呢答案是基类和子类class function { public: class Base { public: //虚析构函数保证能够正确调用child1的析构函数否则调用的是Base的析构函数 virtual ~Base() default; virtual void revoke() 0; }; templateclass T class child1 : public Base { T _t; public: child1(T t) : _t(t) {} void revoke() override {_t();} }; templateclass T function(T t) { _base new child1T(t); } ~function() { delete _base; } private: //无论可调用对象是什么类型它永远是Base的子类 Base* _base; };为了包装器可以像函数一样被调用我们再重载一个()class function { public: class Base { public: //虚析构函数保证能够正确调用child1的析构函数否则调用的是Base的析构函数 virtual ~Base() default; virtual void revoke() 0; }; templateclass T class child1 : public Base { T _t; public: child1(T t) : _t(t) {} void revoke() override {_t();} }; templateclass T function(T t) { _base new child1T(t); } ~function() { delete _base; } void operator()() { _base-revoke(); } private: Base* _base; };到这儿整个包装器的原理大致就结束了不过我们可以发现现在的包装器只能接受无参并且无返回值的可调用对象。这就是为什么定义包装器的时候要传模版类型//不能主模板中偏特化所以先声明主模板 templateclass Ret,class... Args class function; templateclass Ret,class... Args class functionRet(Args...)//这是一种偏特化定义了传模板类型的格式 { public: class Base { public: //虚析构函数保证能够正确调用child1的析构函数否则调用的是Base的析构函数 virtual ~Base() default; virtual Ret revoke(Args...) 0; }; templateclass T class child1 : public Base { T _t; public: child1(T t) : _t(t) {} Ret revoke(Args... args) override {_return _t(args...);} }; templateclass T function(T t) { _base new child1T(t); } ~function() { delete _base; } Ret operator()(Args... args) { return _base-revoke(args...); } private: Base* _base; };
C++——Function原理
众所周知function可以封装任意类型的可调用对象功能十分强大这篇文章主要是想讲解一下function的工作原理。可调用对象有这么几种类型仿函数对象、函数指针、lambda表达式... ... 即使这几种可调用对象的参数和返回值类型相同也会被会被判定为不同的类型毕竟仿函数本质上是类而函数指针是一个函数指针类型。我们首先要解决的问题就是如何接收不同的类型答案是模板class function { public: templateclass T function(T t) { _t t; } }那么问题又来了function类不知道T这个类型如何提前定义一个对象_t去存储传参进来的可调用对象呢答案是基类和子类class function { public: class Base { public: //虚析构函数保证能够正确调用child1的析构函数否则调用的是Base的析构函数 virtual ~Base() default; virtual void revoke() 0; }; templateclass T class child1 : public Base { T _t; public: child1(T t) : _t(t) {} void revoke() override {_t();} }; templateclass T function(T t) { _base new child1T(t); } ~function() { delete _base; } private: //无论可调用对象是什么类型它永远是Base的子类 Base* _base; };为了包装器可以像函数一样被调用我们再重载一个()class function { public: class Base { public: //虚析构函数保证能够正确调用child1的析构函数否则调用的是Base的析构函数 virtual ~Base() default; virtual void revoke() 0; }; templateclass T class child1 : public Base { T _t; public: child1(T t) : _t(t) {} void revoke() override {_t();} }; templateclass T function(T t) { _base new child1T(t); } ~function() { delete _base; } void operator()() { _base-revoke(); } private: Base* _base; };到这儿整个包装器的原理大致就结束了不过我们可以发现现在的包装器只能接受无参并且无返回值的可调用对象。这就是为什么定义包装器的时候要传模版类型//不能主模板中偏特化所以先声明主模板 templateclass Ret,class... Args class function; templateclass Ret,class... Args class functionRet(Args...)//这是一种偏特化定义了传模板类型的格式 { public: class Base { public: //虚析构函数保证能够正确调用child1的析构函数否则调用的是Base的析构函数 virtual ~Base() default; virtual Ret revoke(Args...) 0; }; templateclass T class child1 : public Base { T _t; public: child1(T t) : _t(t) {} Ret revoke(Args... args) override {_return _t(args...);} }; templateclass T function(T t) { _base new child1T(t); } ~function() { delete _base; } Ret operator()(Args... args) { return _base-revoke(args...); } private: Base* _base; };