Templates 具有可变参数和可自定义特征的类模板
我知道这个问题的题目并不好。如果有人能把它弄清楚,我将不胜感激 我的整个问题的简要概述: 我设计了一个通用的Factory类,我已经将它用于许多项目。Factory类使用可变参数来允许我指定0个或多个传递给所创建类的构造函数的参数 当我最初设计这个通用的_工厂类时,我没有将构造的类T作为std::shared_ptr返回的问题。然而,新的需求已经出现,我希望将我的Generic_工厂类调整为更通用的,并允许工厂的用户指定返回的指针类型——std::shared_ptr、std::unique_ptr或T* 有效的解决方案 我通过添加另一个模板参数修改了泛型工厂类。我不喜欢这种方法,因为(a)它不允许我指定默认行为,(b)我发现在阅读代码时,将指针类型作为模板参数有点混乱。然而,它确实起作用。下面是经过测试的泛型_工厂调用,然后是此类的示例使用: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
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; /* ... */ };