Templates 具有可变参数和可自定义特征的类模板

Templates 具有可变参数和可自定义特征的类模板,templates,c++11,sfinae,generic-programming,typetraits,Templates,C++11,Sfinae,Generic Programming,Typetraits,我知道这个问题的题目并不好。如果有人能把它弄清楚,我将不胜感激 我的整个问题的简要概述: 我设计了一个通用的Factory类,我已经将它用于许多项目。Factory类使用可变参数来允许我指定0个或多个传递给所创建类的构造函数的参数 当我最初设计这个通用的_工厂类时,我没有将构造的类T作为std::shared_ptr返回的问题。然而,新的需求已经出现,我希望将我的Generic_工厂类调整为更通用的,并允许工厂的用户指定返回的指针类型——std::shared_ptr、std::unique_p

我知道这个问题的题目并不好。如果有人能把它弄清楚,我将不胜感激

我的整个问题的简要概述:

我设计了一个通用的Factory类,我已经将它用于许多项目。Factory类使用可变参数来允许我指定0个或多个传递给所创建类的构造函数的参数

当我最初设计这个通用的_工厂类时,我没有将构造的类T作为std::shared_ptr返回的问题。然而,新的需求已经出现,我希望将我的Generic_工厂类调整为更通用的,并允许工厂的用户指定返回的指针类型——std::shared_ptr、std::unique_ptr或T*

有效的解决方案

我通过添加另一个模板参数修改了泛型工厂类。我不喜欢这种方法,因为(a)它不允许我指定默认行为,(b)我发现在阅读代码时,将指针类型作为模板参数有点混乱。然而,它确实起作用。下面是经过测试的泛型_工厂调用,然后是此类的示例使用:

    template <class T>
    struct Shared_Pointer{
        using Type = std::shared_ptr<T>;
    };
    template <class T>
    struct Unique_Pointer{
        using Type = std::unique_ptr<T>;
    };
    template <class T>
    struct Raw_Pointer{
        using Type = T*;
    };


    template <
                class AbstractType, 
                template <typename> class Pointer_Type<AbstractType>,
                class...ConstructorArgs>
    class Generic_Factory{

    public:
        static typename Pointer_Type<AbstractType>::Type 
                Construct(std::string key, ConstructorArgs... arguments){
            auto it = Get_Registry()->find(key);
            if (it == Get_Registry()->cend())
                return nullptr;

            auto constructor = it->second;
            return constructor(std::forward<ConstructorArgs>(arguments)...);
        }

        using Constructor_t = std::function<
                typename Pointer_Type<AbstractType>::Type(ConstructorArgs...)>;
        using Registry_t = std::map< std::string, Constructor_t>;

        Generic_Factory(Generic_Factory const&) = delete;
        Generic_Factory& operator=(Generic_Factory const&) = delete;

    protected:
        Generic_Factory(){}
        static Registry_t* Get_Registry();

    private:
        static Registry_t* _registry_;

    };

    template <
                class ConcreteType, 
                class AbstractType, 
                template <typename> class Pointer_Type<AbstractType>, 
                class...ConstructorArgs>
    struct Factory_Registrar : 
                private Generic_Factory<AbstractType, Pointer_Type, ConstructorArgs...>
                {
        using Factory = Generic_Factory<AbstractType, Pointer_Type, ConstructorArgs...>;
        using Constructor_t = typename Factory::Constructor_t;

public:
        Factory_Registrar(std::string const& designator, Constructor_t  object_constructor){
            auto registry = Factory::Get_Registry();
            if (registry->find(designator) == registry->cend())
                registry->insert(std::make_pair(designator, object_constructor));
        }
        unsigned int NO_OP(){ return 0; }
    };

    template <class Return_t, template <typename> class Pointer_Type, class...Args>
    typename Generic_Factory<Return_t, Pointer_Type, Args...>::Registry_t* Generic_Factory<Return_t, Pointer_Type, Args...>::Get_Registry(){
    if (_registry_ == nullptr)
        _registry_ = new Generic_Factory<Return_t, Pointer_Type, Args...>::Registry_t();
    return _registry_;
}

    template <class Return_t, template <typename> class Pointer_Type, class...Args>
    typename Generic_Factory<Return_t, Pointer_Type, Args...>::Registry_t* Generic_Factory<Return_t, Pointer_Type, Args...>::_registry_ = nullptr;
模板
结构共享指针{
使用Type=std::shared\u ptr;
};
样板
结构唯一指针{
使用Type=std::unique\u ptr;
};
样板
结构原始指针{
使用类型=T*;
};
模板<
类抽象类型,
模板类指针类型,
类…构造函数args>
类通用工厂{
公众:
静态类型名指针\u类型::类型
构造(std::字符串键、ConstructorArgs…参数){
auto it=Get_Registry()->find(key);
if(it==Get_Registry()->cend())
返回空ptr;
自动构造器=它->秒;
返回构造函数(std::forward(参数)…);
}
使用构造函数\u t=std::function<
类型名指针类型::类型(构造函数args…>;
使用注册表\u t=std::map;
通用工厂(通用工厂常数&)=删除;
通用工厂&运算符=(通用工厂常量&)=删除;
受保护的:
泛型_工厂(){}
静态注册表\u t*获取注册表();
私人:
静态注册表\u t*\u注册表\u;
};
模板<
类具体类型,
类抽象类型,
模板类指针类型,
类…构造函数args>
结构工厂注册处:
私人通用工厂
{
使用工厂=通用工厂;
使用构造函数\u t=typename工厂::构造函数\u t;
公众:
工厂注册器(标准::字符串常量和指示符、构造函数\u t对象\u构造函数){
自动注册表=工厂::获取注册表();
如果(注册表->查找(指示符)=注册表->cend())
注册表->插入(std::make_pair(指示符、对象\u构造函数));
}
无符号int NO_OP(){return 0;}
};
样板
typename Generic_Factory::Registry_t*Generic_Factory::Get_Registry(){
if(_registry_==nullptr)
_registry_u=new Generic_Factory::registry_t();
返回注册表;
}
样板
typename Generic_Factory::Registry_t*Generic_Factory::_Registry_uu=nullptr;
此泛型类的使用方式如下:

class My_Abstract_Type; // Forward-declaration of abstract type
class Ctor_Arg1; // Forward declaration of arbitrary type, argument to constructor
class Ctor_Arg2; // Forward declaration of arbitrary type, argument to constructor

template <class ConcreteType>
using My_Factory_Registrar =
    Factory_Registrar<ConcreteType, My_Abstract_Type, Shared_Pointer, Ctor_Arg1&&, Ctor_Arg2 const&>;
using My_Factory =
    Generic_Factory<My_Abstract_Type, Shared_Pointer, Ctor_Arg1&&, Ctor_Arg2 const&>;
class My\u Abstract\u Type;//抽象类型的转发声明
类Ctor_Arg1;//将任意类型的声明、参数转发给构造函数
类构造函数Arg2;//将任意类型的声明、参数转发给构造函数
样板
使用我的工厂注册=
工厂注册主任;
使用我的工厂=
通用工厂;
我在具体类中使用宏作为样板注册代码。它只是一个静态变量声明:

class Concrete1{
   /* ...  */
   static My_Factory_Registrar<Concrete1>;
}
class-1{
/* ...  */
静态我的工厂注册;
}
此变量的定义将提供键(字符串)和任何其他参数(如果需要)

我真正想要的

我的理想解决方案是使用traits类来消除指针类型模板参数。我已经尝试过了,通过创建一个traits类和相关的helper类,但是这不能正常工作。我自己的尝试涉及为每个抽象类型专门化traits类(至少是那些我希望与std::shared_ptr不同的类型),但这有很多问题。其中大部分我甚至还没有确定(不会编译,代码只是“闻起来”有问题——我觉得这是一种错误的方法,所以在浪费大量时间在我认为是错误的事情上之前,我需要一些指导

我真的希望能够使用一种声明性语法,类似于泛型工厂类的其他用法——理想情况下是某种别名

如有任何想法和/或建议,将不胜感激

谢谢并致以最良好的祝愿,
Shmuel

经过一点工作和一些额外的思考,我已经通过使用Traits方法成功地使代码正常工作,如“我真正想要的”一节所述

简要总结(我将复制下面的完整代码):

  • 我试图使我的泛型工厂更加泛型——允许我选择指针的类型(我可能可以扩展它,而不需要通过值或引用返回对象)
  • 最简单的方法是添加另一个模板参数,但我发现这很难看:
    • 没有默认参数
    • 使界面更加混乱
  • 基于特征的方法是理想的,但我在实现这一点上遇到了困难
  • T
       namespace internal{
        template <typename T, bool> struct Factory_Pointer_Traits_Impl;
        template<typename T> struct CheckForType;
        }
    
        template <typename T>
        struct Factory_Pointer_Traits
        {
            typedef typename internal::Factory_Pointer_Traits_Impl<T, internal::CheckForType<T>::value>::type pointer_t;
        };
    
        namespace internal {
    
            template <typename T, bool>
            struct Factory_Pointer_Traits_Impl
            {
                typedef Shared_Pointer<T> type;
            };
    
           template <typename T>
           struct Factory_Pointer_Traits_Impl<T, true>
           {
               typedef typename T::Pointer_Type type;
           };   
    
           template<typename T>
           struct CheckForType
           {
           private:
               typedef char                      yes;
               typedef struct { char array[2]; } no;   
    
               template<typename C> static yes test(typename C::Pointer_Type*);
               template<typename C> static no  test(...);
           public:
               static const bool value = sizeof(test<T>(0)) == sizeof(yes);
           };
        }
    
        template <class AbstractType, class...ConstructorArgs>
        class Generic_Factory{
            using Pointer_T = typename core::Factory_Pointer_Traits<AbstractType>::pointer_t::type;
        public:
            /* ... */
        };
    
    class IPerson{
        public:
            using Pointer_Type = Unique_Pointer<IPerson>;
            std::string first_name, last_name;
            /* ... */
        };
    
    #define FACTORY_POINTER_TYPE(CLASS_NAME, POINTER_TYPE)  \
    using Pointer_Type = fx::core::POINTER_TYPE<CLASS_NAME>;
    
    class IPerson{
        public:
            FACTORY_POINTER_TYPE(IPerson, Unique_Pointer);
            std::string first_name, last_name;
            /* ... */
        };