C++ C++;handle/body类由模板参数包自动组成。这能改进吗?

C++ C++;handle/body类由模板参数包自动组成。这能改进吗?,c++,templates,variadic-templates,C++,Templates,Variadic Templates,问题: 多个组件希望共享相同的不可变数据(任意类型),但每个组件都有一组不同的接口需求 例如,组件A可能要求有一个名为hash\u code(const object&)的可用自由函数,组件B可能要求该对象有一个名为type(const object&)的可用自由函数 如果组件C生成一个指向某个对象O的共享指针,该对象有一个名为hash_code的自由函数和一个名为type的自由函数,那么组件C可以与组件a和B共享O,因为可以推导出兼容的接口 现在,我们已经解耦了多态标识类型,并且没有复制开销

问题:

多个组件希望共享相同的不可变数据(任意类型),但每个组件都有一组不同的接口需求

例如,组件A可能要求有一个名为
hash\u code(const object&)
的可用自由函数,组件B可能要求该对象有一个名为
type(const object&)
的可用自由函数

如果组件C生成一个指向某个对象O的共享指针,该对象有一个名为
hash_code
的自由函数和一个名为
type
的自由函数,那么组件C可以与组件a和B共享O,因为可以推导出兼容的接口

现在,我们已经解耦了多态标识类型,并且没有复制开销

我实现这一点的方法是有一个模板
句柄
类,它充满了
方法描述符
(更多模板类):

以下是一个完整的工作测试程序,有两种方法:

一个是手动编写handle类,另一个是允许模板扩展为我编写它

目前,有两个问题:

  • 在模板版本中,为了创建模型/概念层次结构,我不得不求助于虚拟继承
  • 描述每个方法调用需要一个包含3种相关类型的复杂类:多态概念、该概念的类型化模型以及句柄的接口组件
  • 必须有一种更优雅的方式

    #include <iostream>
    #include <utility>
    #include <string>
    #include <typeindex>
    #include <boost/functional/hash.hpp>
    
    
    // some arbitrary type which supports hashing and type
    struct algo1_ident
    {
        std::type_info const& _algo_type = typeid(algo1_ident);
        std::string arg1;
        std::string arg2;
    };
    
    auto type(algo1_ident const& ident) -> std::type_info const&
    {
        return ident._algo_type;
    }
    
    auto hash_code(algo1_ident const& ident) -> std::size_t
    {
        auto seed = ident._algo_type.hash_code();
        boost::hash_combine(seed, ident.arg1);
        boost::hash_combine(seed, ident.arg2);
        return seed;
    }
    
    
    //
    // manual approach
    //
    // step one: define a complete concept
    struct algo_ident_concept
    {
        virtual std::type_info const & impl_type(const void* p) const = 0;
        virtual std::size_t impl_hash_code(const void* p) const = 0;
    
    };
    
    //
    // step two: define the model of that concept
    //
    
    template<class Impl>
    struct algo_ident_model : algo_ident_concept
    {
        std::type_info const& impl_type(const void* p) const override
        {
            return type(ref(p));
        }
    
        std::size_t impl_hash_code(const void* p) const override
        {
            return hash_code(ref(p));
        }
    
    private:
        static const Impl& ref(const void* p) {
            return *static_cast<Impl const*>(p);
        }
    };
    
    //
    // step three: write the handle class
    //
    template<template <class> class Model, template <class> class PtrType>
    struct algo_ident_handle
    {
        template<class Impl> struct model_tag {};
    
        template<class Impl>
        algo_ident_handle(std::shared_ptr<const Impl> ptr)
        : _impl(std::move(ptr))
        , _access_model(make_access_model(model_tag<const Impl>()))
        {}
    
        template<class Impl>
        algo_ident_concept const* make_access_model(model_tag<Impl>)
        {
            static struct : algo_ident_concept
            {
                std::type_info const& impl_type(const void* p) const override
                {
                    using ::type;
                    return type(ref(p));
                }
    
                std::size_t impl_hash_code(const void* p) const override
                {
                    using ::hash_code;
                    return hash_code(ref(p));
                }
    
            private:
                static const Impl& ref(const void* p) {
                    return *static_cast<Impl const*>(p);
                }
            } const _model {};
            return std::addressof(_model);
        }
    
        PtrType<const void> _impl;
        const algo_ident_concept* _access_model;
    
        //
        // interface
        //
    
        std::size_t hash_code() const {
            return _access_model->impl_hash_code(_impl.get());
        }
    
        std::type_info const& type() const {
            return _access_model->impl_type(_impl.get());
        }
    
    };
    
    
    //
    // now the componentised approach
    //
    
    // step 1: define the concept, model and handle interface for supporting the
    //         method `hash_code`
    //         This can go in a library
    
    template<class Host>
    struct has_hash_code
    {
        struct concept
        {
            virtual std::size_t hash_code(const void*) const = 0;
        };
    
        template<class Impl> struct model : virtual concept
        {
            std::size_t hash_code(const void* p) const override
            {
                using ::hash_code;
                return hash_code(*static_cast<const Impl*>(p));
            }
        };
    
        struct interface
        {
            std::size_t hash_code() const
            {
                auto self = static_cast<const Host*>(this);
                return self->model()->hash_code(self->object());
            }
        };
    };
    
    // step 2: define the concept, model and handle interface for supporting the
    //         method `type`
    //         This can go in a library
    
    template<class Host>
    struct has_type
    {
        struct concept
        {
            virtual std::type_info const& type(const void*) const = 0;
        };
    
        template<class Impl> struct model : virtual concept
        {
            std::type_info const& type(const void* p) const override
            {
                using ::type;
                return type(*static_cast<const Impl*>(p));
            }
        };
    
        struct interface
        {
            std::type_info const& type() const
            {
                auto self = static_cast<const Host*>(this);
                return self->model()->type(self->object());
            }
        };
    };
    
    // step 3: provide a means of turning a pack of methods into a concept base class
    
    template<class Host, template<class>class...Methods>
    struct make_concept
    {
        using type = struct : virtual Methods<Host>::concept... {};
    };
    
    // step 4: provide a means of turning a pack of methods into a model class
    
    template<class Impl, class Host, template<class>class...Methods>
    struct make_model
    {
        using concept_type = typename make_concept<Host, Methods...>::type;
        using type = struct : Methods<Host>::template model<Impl>... , concept_type {};
    
        static auto apply()
        {
            static const type _model {};
            return std::addressof(_model);
        }
    };
    
    // step 5: provide a means of turning a pack of methods into an interface
    
    template<class Host, template<class>class...Methods>
    struct make_interface
    {
        using type = struct : Methods<Host>::interface... {};
    };
    
    // step 6: convenience class in which to store the object pointer and the
    //         polymorphic model
    
    template<class ConceptType>
    struct storage
    {
        storage(std::shared_ptr<const void> object, const ConceptType* concept)
        : _object(object), _model(concept)
        {}
    
        const void* object() const { return _object.get(); }
        const ConceptType* model() const { return _model; }
    
        std::shared_ptr<void const> _object;
        const ConceptType* _model;
    };
    
    // step 7: build a handle which supports the required methods while
    //         storing a shared_ptr to the object
    
    template<template<class> class...Methods>
    struct handle
    : make_interface<handle<Methods...>, Methods...>::type
    {
        using this_class = handle;
        using concept_type = typename make_concept<this_class, Methods...>::type;
        using storage_type = storage<concept_type>;
    
        template<class Impl>
        static auto create_storage(std::shared_ptr<Impl> ptr)
        {
            using model_type = typename make_model<Impl, this_class, Methods...>::type;
            const model_type* pm = make_model<Impl, this_class, Methods...>::apply();
            return storage_type(ptr, pm);
        }
    
        template<class Impl>
        handle(std::shared_ptr<Impl> ptr)
        : _storage(create_storage(ptr))
        {}
    
        const void* object() const { return _storage.object(); }
        const concept_type* model() const { return _storage.model(); }
    
    
        storage<concept_type> _storage;
    };
    
    
    //
    // another arbitrary object which also supports the hash_code and type protocols
    
    namespace algo2 {
        struct algo2_ident
        {
            std::type_info const& _algo_type = typeid(algo2_ident);
            std::string arg1 = "foo";
            std::string arg2 = "bar";
        };
    
        auto type(algo2_ident const& ident) -> std::type_info const&
        {
            return ident._algo_type;
        }
    
        auto hash_code(algo2_ident const& ident) -> std::size_t
        {
            auto seed = ident._algo_type.hash_code();
            boost::hash_combine(seed, ident.arg1);
            boost::hash_combine(seed, ident.arg2);
            return seed;
        }
    }
    
    //
    // test
    //
    
    int main(int argc, const char * argv[])
    {
        algo_ident_handle<algo_ident_model, std::shared_ptr> h1 = std::make_shared<const algo1_ident>();
        algo_ident_handle<algo_ident_model, std::shared_ptr> h2 = std::make_shared<const algo2::algo2_ident>();
    
        //
        // prove that an h1 is equivalent to the object of which it is a handle
        //
        algo1_ident chk1 {};
        std::cout << h1.hash_code() << std::endl;
        std::cout << hash_code(chk1) << std::endl;
    
        algo2::algo2_ident chk {};
    
        std::cout << h2.hash_code() << std::endl;
        std::cout << hash_code(chk) << std::endl;
    
        //
        // same proof for the composed handle
        //
        handle<has_hash_code, has_type> ht1 = std::make_shared<const algo2::algo2_ident>();
        std::cout << ht1.hash_code() << std::endl;
        std::cout << hash_code(chk) << std::endl;
    
        return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    //支持哈希和类型转换的任意类型
    结构算法识别
    {
    std::type_info const&_algo_type=typeid(algo1_ident);
    std::字符串arg1;
    std::字符串arg2;
    };
    自动类型(algo1_ident const&ident)->std::type_info const&
    {
    返回标识算法类型;
    }
    自动哈希代码(algo1_ident const&ident)->std::size\t
    {
    自动种子=识别算法类型。哈希代码();
    boost::hash_combine(种子,标识arg1);
    boost::hash_combine(种子,标识arg2);
    返回种子;
    }
    //
    //人工进近
    //
    //第一步:定义一个完整的概念
    结构算法识别概念
    {
    虚拟std::type_info const&impl_type(const void*p)const=0;
    虚拟std::size\t impl\u hash\u code(const void*p)const=0;
    };
    //
    //第二步:定义该概念的模型
    //
    模板
    结构算法识别模型:算法识别概念
    {
    std::type_info const和impl_type(const void*p)const override
    {
    返回类型(参考(p));
    }
    std::size\u t impl\u hash\u代码(const void*p)const override
    {
    返回哈希_码(ref(p));
    }
    私人:
    静态常量Impl&ref(常量void*p){
    返回*static_cast(p);
    }
    };
    //
    //第三步:编写handle类
    //
    模板
    结构算法识别句柄
    {
    模板结构模型_标记{};
    模板
    算法识别句柄(std::shared_ptr ptr)
    :_impl(std::move(ptr))
    ,_access_model(生成_access_model(model_tag()))
    {}
    模板
    算法识别概念常量*生成访问模型(模型标签)
    {
    静态结构:算法识别概念
    {
    std::type_info const和impl_type(const void*p)const override
    {
    使用::type;
    返回类型(参考(p));
    }
    std::size\u t impl\u hash\u代码(const void*p)const override
    {
    使用::hash_代码;
    返回哈希_码(ref(p));
    }
    私人:
    静态常量Impl&ref(常量void*p){
    返回*static_cast(p);
    }
    }const_模型{};
    返回std::addressof(_model);
    }
    PtrType _impl;
    常量算法识别概念*.\u访问模型;
    //
    //接口
    //
    std::size\u t hash\u code()常量{
    返回_access_model->impl_hash_代码(_impl.get());
    }
    std::type_info const和type()const{
    返回_access_model->impl_type(_impl.get());
    }
    };
    //
    //现在是组件化方法
    //
    //步骤1:定义概念、模型和句柄接口,以支持
    //方法`hash_码`
    //这可以放在图书馆里
    模板
    结构具有\u哈希\u代码
    {
    结构概念
    {
    虚拟标准::大小\u t哈希\u代码(const void*)const=0;
    };
    模板结构模型:虚拟概念
    {
    std::size\u t散列码(const void*p)const覆盖
    {
    使用::hash_代码;
    返回hash_代码(*static_cast(p));
    }
    };
    结构接口
    {
    std::size\u t hash\u code()常量
    {
    自动自=静态施法(本);
    返回self->model()->hash_代码(self->object());
    }
    };
    };
    //步骤2:定义概念、模型和句柄接口,以支持
    //方法类型`
    //这可以放在图书馆里
    模板
    结构具有\u类型
    {
    结构概念
    {
    虚拟std::type_info const&type(const void*)const=0;
    };
    模板结构模型:虚拟概念
    {
    std::type_info const&type(const void*p)const override
    {
    使用::type;
    返回类型(*static_cast(p));
    }
    };
    结构接口
    {
    std::type_info const和type()const
    {
    自动自=静态施法(本);
    返回self->model()->type(self->object());
    }
    };
    };
    //步骤3:提供一种将方法包转换为概念基类的方法
    模板
    结构制造概念
    {
    使用type=struct:virtualmethods::concept…{};
    };
    //步骤4:提供一种将方法包转换为模型类的方法
    模板
    结构make_模型
    {
    使用concept_type=typename生成_concept::type;
    使用type=struct:Methods::template model…,concept_type{};
    静态自动应用()
    {
    静态常量类型_模型{};
    返回std::addressof(_model);
    }
    };
    //第五步:提供一种方法来转动一包甲醇
    
    // To avoid conflict with name and ADL.
    namespace detail
    {
        template <typename T>
        decltype(auto) callHashCode(T&& t) { return hash_code(std::forward<T>(t)); }
    
        template <typename T>
        decltype(auto) callType(T&& t) { return type(std::forward<T>(t)); }
    }
    
    class HashRunner
    {
    public:
        template <typename T>
        HashRunner(std::shared_ptr<T> p) :
        hash_code([=](){ return detail::callHashCode(*p); })
        {}
    
        std::function<std::size_t()> hash_code;
    };
    
    class TypeRunner
    {
    public:
        template <typename T>
        TypeRunner(std::shared_ptr<T> p) :
        type([=]() -> const std::type_info& { return detail::callType(*p); })
        {}
    
        std::function<const std::type_info&()> type;
    };
    
    template <typename ... Ts>
    class MyHandle : public Ts...
    {
    public:
        template <typename T>
        MyHandle(std::shared_ptr<T> p) : Ts(p)... {}
    };