zoukankan      html  css  js  c++  java
  • C++函数委托

    环境:

      win7_x64旗舰版、VS2015企业版

    场景:

      C++标准库提供std::function类来将一个对象的调用操作封装在一个对象内部,然后可以委托调用,但是有一些弊端,例如下面的需求:

        我们需要将调用操作封装存储到一个map中,来实现观察者模式或信号槽,由于std::function是在编译期确定类型,导致你无法将不同类型的std::function(例如std::function<void()>和std::function<void(int)>)放入同一个map中。

      function_delegate里就是为了解决上面的问题而写的。

    实现代码:

     function_delegate.h

    /**
    * @file    function_delegate.h
    * @brief   函数委托
    * @author  DC
    * @date    2019-04-16
    * @note
    * @example
    *          class my_class
    *          {
    *          public:
    *              void test(int a, double b)
    *              {
    *              }
    *          };
    *
    *          my_class my;
    *          function_delegate<> delegate(&my, &my_class::test);
    *          delegate(1, 2.0);
    *
    */
    
    #ifndef FUNCTION_DELEGATE_H_
    #define FUNCTION_DELEGATE_H_
    
    namespace function_delegate_pri
    {
        ///< 对象成员函数指针
        class member_ptr
        {
        public:
            ///< 哈希函数
            typedef std::_Bitwise_hash<member_ptr> hash;
            ///< 构造函数
            template<class T, class Func>
            member_ptr(T* obj, Func func)
            {
                obj_ = obj;
                *(Func*)&func_ = func;
            }
            ///< 小于函数
            bool operator <(const member_ptr& ptr) const
            {
                if (func_[0] != ptr.func_[0]) {
                    return func_[0] < ptr.func_[0];
                }
                if (func_[1] != ptr.func_[1]) {
                    return func_[1] < ptr.func_[1];
                }
                return obj_ < ptr.obj_;
            }
            ///< 相等函数
            bool operator ==(const member_ptr& ptr) const
            {
                if (func_[0] != ptr.func_[0]) {
                    return false;
                }
                if (func_[1] != ptr.func_[1]) {
                    return false;
                }
                return obj_ == ptr.obj_;
            }
            ///< 调用函数
            template
            <
                typename T,
                typename U,
                typename Result,
                typename ... Args
            >
            Result invoke(Args... args)
            {
                typedef Result(U::*Call)(Args...);
                Call call = *(Call*)&func_;
                return (((T*)obj_)->*call)(args...);
            }
    
            void* obj_{nullptr};     ///< 对象指针
            ///< 对象成员函数需要使用三个指针,C++多重虚拟继承导致
            void* func_[3]{nullptr}; ///< 类成员函数指针
        };
    
        ///< 函数委托
        template<class Strategy = void>
        class delegate_impl
        {
        public:
            ///< 设置对象和成员函数
            template
            <
                typename T,
                typename U,
                typename Result,
                typename ... Args
            >
            delegate_impl(T* ptr, Result(U::*fn)(Args...)) : refcnt_(ptr), ptr_(ptr, fn)
            {
                typedef Result(*Invoke)(member_ptr*, Args...);
                Invoke call = &delegate_impl::invoke<T, U, Result, Args...>;
                invoke_ = call;
            }
    
            bool operator <(const delegate_impl& func) const
            {
                if (invoke_ != func.invoke_) {
                    return invoke_ < func.invoke_;
                }
                return ptr_ < func.ptr_;
            }
    
            ///< 调用成员函数
            template
            <
                typename Result = void,
                typename ... Args
            >
            Result operator()(Args... args) const
            {
                typedef Result(*Invoke)(member_ptr*, Args...);
                Invoke call = (Invoke)invoke_;
                return call((member_ptr*)&ptr_, args...);
            }
    
            Strategy* object() const { return refcnt_; }
    
        private:
            template
            <
                typename T,
                typename U,
                typename Result,
                typename ... Args
            >
            static Result invoke(member_ptr* ptr, Args... args)
            {
                return ptr->invoke<T, U, Result>(args...);
            }
    
            Strategy*       refcnt_{ nullptr };   ///< 
            member_ptr    ptr_;                 ///< 成员函数指针
            void*           invoke_{ nullptr };   ///< invoke函数地址
        };
    
        template<>
        class delegate_impl<void>
        {
        public:
            ///< 设置对象和成员函数
            template
            <
                typename T,
                typename U,
                typename Result,
                typename ... Args
            >
            delegate_impl(T* ptr, Result(U::*fn)(Args...)) : ptr_(ptr, fn)
            {
                typedef Result(*Invoke)(member_ptr*, Args...);
                Invoke call = &delegate_impl::invoke<T, U, Result, Args...>;
                invoke_ = call;
            }
    
            bool operator <(const delegate_impl& func) const
            {
                if (invoke_ != func.invoke_) {
                    return invoke_ < func.invoke_;
                }
                return ptr_ < func.ptr_;
            }
    
            ///< 调用成员函数
            template
            <
                typename Result = void,
                typename ... Args
            >
            Result operator()(Args... args) const
            {
                typedef Result(*Invoke)(member_ptr*, Args...);
                Invoke call = (Invoke)invoke_;
                return call((member_ptr*)&ptr_, args...);
            }
    
        private:
            template
            <
                typename T,
                typename U,
                typename Result,
                typename ... Args
            >
            static Result invoke(member_ptr* ptr, Args... args)
            {
                return ptr->invoke<T, U, Result>(args...);
            }
    
            member_ptr    ptr_;                 ///< 成员函数指针
            void*         invoke_{ nullptr };   ///< invoke函数地址
        };
    }
    
    using function_ptr = function_delegate_pri::member_ptr;
    template<class Strategy = void>
    using function_delegate = function_delegate_pri::delegate_impl<Strategy>;
    
    #endif ///< !FUNCTION_DELEGATE_H_
    View Code

    测试代码:

    function_delegate_test.h

    #include <iostream>
    #include <vector>
    #include <functional>
    #include "time_stamp.h"
    #include "function_delegate.h"
    
    namespace function_delegate_unit_test 
    {
        class testa
        {
        public:
            virtual int testa1(int n)
            {
                std::cout << "testa::testa1	param:" << n << ", data:";
                for (int v : avec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
            int testa2(int n)
            {
                std::cout << "testa::testa2	param:" << n << ", data:";
                for (int v : avec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
    
        protected:
            std::vector<int> avec_{ 1, 2, 3 };
        };
    
        class testb
        {
        public:
            virtual int testb1(int n)
            {
                std::cout << "testb::testb1	param:" << n << ", data:";
                for (int v : bvec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
            int testb2(int n)
            {
                std::cout << "testb::testb2	param:" << n << ", data:";
                for (int v : bvec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
    
        protected:
            std::vector<int> bvec_{ 4, 5, 6 };
        };
    
        class testc : public testa, public testb
        {
        public:
            int testa1(int n) override
            {
                std::cout << "testc::testa1	param:" << n << ", data:";
                for (int v : bvec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return testa::testa1(n);
            }
    
            int testb1(int n) override
            {
                std::cout << "testc::testb1	param:" << n << ", data:";
                for (int v : bvec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return testb::testb1(n);
            }
    
            int test(int n)
            {
                std::cout << "testc::testb1	param:" << n << ", data:";
                for (int v : avec_) {
                    std::cout << v << ",";
                }
                for (int v : bvec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
        };
    
        class testd
        {
        public:
            virtual int test(int n)
            {
                std::cout << "testd::test	param:" << n << ", data:";
                for (int v : dvec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
            int testd1(int n)
            {
                std::cout << "testd::testd1	param:" << n << ", data:";
                for (int v : dvec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
    
        protected:
            std::vector<int> dvec_{ 1, 2, 3 };
        };
    
        class teste
        {
        public:
            virtual int test(int n)
            {
                std::cout << "teste::test	param:" << n << ", data:";
                for (int v : evec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
            int teste1(int n)
            {
                std::cout << "teste::teste1	param:" << n << ", data:";
                for (int v : evec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
    
        protected:
            std::vector<int> evec_{ 1, 2, 3 };
        };
    
        class testf : public virtual testd, public virtual teste
        {
        public:
            virtual int test(int n) override
            {
                std::cout << "teste::test	param:" << n << ", data:";
                for (int v : dvec_) {
                    std::cout << v << ",";
                }
                for (int v : evec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
    
                testd::test(n);
                teste::test(n);
                return n;
            }
            int testf1(int n)
            {
                std::cout << "testf::testf1	param:" << n << ", data:";
                for (int v : dvec_) {
                    std::cout << v << ",";
                }
                for (int v : evec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
        };
    
        class testg
        {
        public:
            int test(int n)
            {
                std::cout << "testg::test	param:" << n << ", data:";
                for (int v : gvec_) {
                    std::cout << v << ",";
                }
                std::cout << std::endl;
                return n;
            }
    
        protected:
            std::vector<int> gvec_{ 1, 2, 3 };
        };
    
        ///< 单元测试
        void test()
        {
            std::cout << "function_delegate_unit_test start" << std::endl;
            ///< TEST testa
            testa a;
            {
                function_delegate<> delegate(&a, &testa::testa1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&a, &testa::testa2);
                delegate(1000);
            }
    
            ///< TEST testb
            testb b;
            {
                function_delegate<> delegate(&b, &testb::testb1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&b, &testb::testb2);
                delegate(1000);
            }
    
            ///< TEST testc
            testc c;
            {
                function_delegate<> delegate(&c, &testa::testa1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&c, &testa::testa2);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&c, &testb::testb1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&c, &testb::testb2);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&c, &testc::testa1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&c, &testc::testa2);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&c, &testc::testb1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&c, &testc::testb2);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&c, &testc::test);
                delegate(1000);
            }
    
            ///< TEST testd
            testd d;
            {
                function_delegate<> delegate(&d, &testd::testd1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&d, &testd::test);
                delegate(1000);
            }
    
            ///< TEST teste
            teste e;
            {
                function_delegate<> delegate(&e, &teste::teste1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&e, &teste::test);
                delegate(1000);
            }
    
            ///< TEST testf
            testf f;
            {
                function_delegate<> delegate(&f, &testd::testd1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&f, &testd::test);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&f, &teste::teste1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&f, &teste::test);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&f, &testf::testd1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&f, &testf::teste1);
                delegate(1000);
            }
            {
                function_delegate<> delegate(&f, &testf::test);
                delegate(1000);
            }
    
            ///< TEST testg
            testg g;
            {
                function_delegate<> delegate(&g, &testg::test);
                delegate(1000);
            }
            std::cout << "function_delegate_unit_test end" << std::endl;
        }
    }
    
    namespace function_delegate_efficiency_test
    {
        class testa
        {
        public:
            int test(int n)
            {
                return n + 1;
            }
        };
    
        class testb
        {
        public:
            virtual int test(int n)
            {
                return n + 1;
            }
        };
        class testc : public testb
        {
        public:
            int test(int n) override
            {
                return n + 2;
            }
        };
    
        ///< 性能测试
        void test(int count)
        {
            std::cout << "function_delegate_efficiency_test start" << std::endl;
            testa a;
            {
                time_stamp ts;
                for (int i = 0; i < count; ++i) {
                    a.test(i);
                }
                double tm = ts.milliseconds();
                std::cout << "count:" << count << "	c++ object call:		" << tm << "(ms)" << std::endl;
            }
            {
                time_stamp ts;
                std::function<int(int)> func = std::bind(&testa::test, &a, std::placeholders::_1);
                for (int i = 0; i < count; ++i) {
                    func(i);
                }
                double tm = ts.milliseconds();
                std::cout << "count:" << count << "	std::function call:		" << tm << "(ms)" << std::endl;
            }
            {
                time_stamp ts;
                function_delegate<> delegate(&a, &testa::test);
                for (int i = 0; i < count; ++i) {
                    delegate(i);
                }
                double tm = ts.milliseconds();
                std::cout << "count:" << count << "	delegate call:			" << tm << "(ms)" << std::endl;
            }
    
            testc c;
            testb* pb = &c;
            {
                time_stamp ts;
                for (int i = 0; i < count; ++i) {
                    pb->test(i);
                }
                double tm = ts.milliseconds();
                std::cout << "count:" << count << "	c++ pointer virtual call:	" << tm << "(ms)" << std::endl;
            }
            {
                time_stamp ts;
                std::function<int(int)> func = std::bind(&testb::test, pb, std::placeholders::_1);
                for (int i = 0; i < count; ++i) {
                    func(i);
                }
                double tm = ts.milliseconds();
                std::cout << "count:" << count << "	std::function virtual call:	" << tm << "(ms)" << std::endl;
            }
            {
                time_stamp ts;
                function_delegate<> delegate(pb, &testb::test);
                for (int i = 0; i < count; ++i) {
                    delegate(i);
                }
                double tm = ts.milliseconds();
                std::cout << "count:" << count << "	delegate virtual call:		" << tm << "(ms)" << std::endl;
            }
            std::cout << "function_delegate_efficiency_test end" << std::endl;
        }
    }
    View Code

      1)其中time_stamp.h包含一个计时类time_stamp的实现,这里没贴代码,可以自己实现。

      2)function_delegate类使用成员data_[0]、data_[1]和data_[2]存储成员函数指针是为了处理被委托的类存在多重继承的情况(用于动态调整this指针,编译器自动调整),如果只使用一个void*存储会发生崩溃。

      注意:这里有个奇怪的现象,对于使用虚拟继承类成员函数,在我的台式机上测试只需要使用data_[0]和data_[1]即可,而在我的笔记本上测试需要使用data_[0]、data_[1]和data_[2] ,所以我统一使用data_[3]存储。

    扩展:

      1)function_delegate类可以用于实现观察者模式和信号槽等,后面会有单独的文章说明。

      2)关于C++ 成员函数指针使用两个void*存储的原因:https://www.oschina.net/translate/wide-pointers?cmp

  • 相关阅读:
    Win7系统中打开exe 无反应
    IE 浏览器主页劫持 如何修复
    win10 airpods显示已配对,但就是连不上怎么办?
    tp5 layui 渲染 时间戳转换为日期时间格式
    为什么要设置 繁琐的密码
    美食摄影 – 明确目的
    MsMpEng.exe进程停止删除或弹出设备,导致移动硬盘无法正常弹出,怎么办?
    单抗热门靶点 | VEGF | TNF-α | CD20 | HER2 | PD-1 | IL-6R | CD47
    EZH2 | Ezh2 | 组蛋白甲基化酶/组蛋白甲基转移酶
    宇宙微波背景辐射 | 著名实验
  • 原文地址:https://www.cnblogs.com/dongc/p/10693000.html
Copyright © 2011-2022 走看看