• C++模板之类型与数据绑定


    有时候我们需要将类型与一些数据进行绑定,例如我们一般通过单例,将字符串与一个函数关联(一般称之为注册),之后通过字符串创建相关联的对象

    class A {
    public:
        static A* Create() { return new A(); }
    }; 

    然后像这样:

    Instance::Register("A", A::Create);
    A* a = Instance::Create("A");

    用字符串进行绑定,不是很方便,如果字符串拼写错了,在整个编译期不会有任何提示,而且字符串是没有代码自动提示的,这样出错率大大增加了,当然你可以复制/粘贴;如果我们能够将一个类型与数据进行绑定,通过类型获取与之相关的数据,一是类型有代码自动提示的(一般拼写前几个字符就可以完成整个输入),及时你自己拼写出错了,没有定义这个类型,编译器编译时也会报错。这里我们使用函数模板,理论上不同的类型,会实例化为不同的函数,我们可以使用函数地址作为标识这个类型的key。

    TypeBind.h

    #ifndef _Type_Bind_H_
    #define _Type_Bind_H_
    
    #include <assert.h>
    #include <map>
    
    template<class _Value>
    class TypeBind {
    public:
        template<class _Type>
        void bind(_Value value) {
            m_map.insert(std::make_pair(TypeDefine<_Type>, value));
        }
    
        template<class _Type>
        _Value& find() {
            std::map<TypeDefineIndifiry, _Value>::iterator iter = m_map.find(TypeDefine<_Type>);
            assert(iter != m_map.end());
            return iter->second;
        }
    
    private:
        template<class T>
        static void TypeDefine(char _ch) { static char ch = _ch; }
        typedef void(*TypeDefineIndifiry)();
    
        std::map<TypeDefineIndifiry, _Value> m_map;
    };
    
    #endif
    这里我们使用的是
    “template<class T> static void TypeDefine(char _ch) { static char ch = _ch; }“函数
    而没有使用
    "template<class T> static void TypeDefine() {}"函数
    原因是生成Release版本时,编译器会进行优化,如果函数的内容是一致的,最后只会生成一个函数(函数的名称不相同,但是内容是一样,也是相同的结果),如果所有类型的函数地址是一致的,就无法使用给每个类型一个标识(函数地址)

    test.cpp

    #include "TypeBind.h"
    
    typedef void*(*CreateCallback)(); // 创建函数的指针
    class ObjectCreateFactory {
        public:
        /**   注册
        *    @T             绑定的类型
        *    @callback      对象创建函数
        */
        template<class T>
        void Register(CreateCallback callback) {
            m_map.bind<T>(callback);
        }
        /**   创建对象
        *    @T            创建对象的类型
        *    @return       创建的对象
        */
        template<class T>
        T* Create() {
            CreateCallback callback = m_map.find<T>();
            return (T*)callback();
        }
    
        static ObjectCreateFactory& Instance() {
            static ObjectCreateFactory* factory = nullptr;
            if (!factory)
                factory = new ObjectCreateFactory();
            return *factory;
        }
    private:
        ObjectCreateFactory() {}
        TypeBind<CreateCallback> m_map;
    };
    
    class A {
    public:
        static A* Create() { return new A(); }
    };
    
    class B {
    public:
        static B* Create() { return new B(); }
    };
    // 注册
    ObjectCreateFactory::Instance().Register<A>((CreateCallback)A::Create);
    ObjectCreateFactory::Instance().Register<B>((CreateCallback)B::Create);
    // 创建
    A* a = ObjectCreateFactory::Instance().Create<A>();
    B* b = ObjectCreateFactory::Instance().Create<B>();
  • 相关阅读:
    2016工作目标
    Android简化xml sax解析
    dynamic-load-apk插件原理整理
    Spring boot 拾遗 —— Spring Cache 扩展 Duration
    Spring boot 拾遗 —— Spring Cache 使用 Jackson 与 自定义 TTL
    Spring boot 拾遗 —— 错误验证
    简化 Java 代码 ——(一)使用 PropertyMapper
    Java 开源项目 OpenFeign —— feign 结合 SpringBoot
    Java 开源项目 OpenFeign —— feign 的基本使用
    Java 定时任务 Quartz (三)—— 并发
  • 原文地址:https://www.cnblogs.com/dongc/p/4903020.html
Copyright © 2020-2023  润新知