我知道这个问题的标题并不是很好。如果有人能够更清楚地解决它,我会很感激。
我的整体问题简要概述:
我有一个我设计的通用工厂类,我已用于许多项目。 Factory类使用可变参数来允许我指定传递给已创建类的构造函数的0个或多个参数。
当我最初设计这个Generic_Factory类时,我没有将构造的类T作为std :: shared_ptr返回的问题。但是,出现了新的要求,我想使我的Generic_Factory类更通用,并允许工厂用户指定返回的指针类型 - std :: shared_ptr,std :: unique_ptr或T *
工作解决方案
我通过添加另一个模板参数来修改Generic_Factory类。我不喜欢这种方法,因为(a)它不允许我指定默认行为,(b)我发现将Pointer_Type作为模板参数在阅读代码时有点混乱。然而,它确实有效。下面是测试的Generic_Factory调用,然后使用此类的示例:
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;
此泛型类的用法如下:
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 Concrete1{
/* ... */
static My_Factory_Registrar<Concrete1>;
}
如果需要,此变量的定义将提供键(字符串)和任何其他参数。
我理想的解决方案是使用traits类来消除Pointer_Type模板参数。我已经通过创建一个带有相关辅助类的traits类来尝试这个,但这并没有正常工作。我自己的尝试涉及尝试为每个AbstractType特化traits类(至少那些我想与std :: shared_ptr不同的那些),但是有很多问题。其中大部分我甚至都没有确定(不会编译,而且代码只是闻起来有点错误 - 我觉得这是错误的方法,所以我&#39;在浪费大量时间在我真正认为是错误的事情之前,我要求一些指导。
我真的希望能够使用类似于Generic_Factory类的其余使用的声明性语法 - 理想情况下是某种类型的别名。
非常感谢任何想法和/或建议。
谢谢和最诚挚的问候, 什穆埃尔
答案 0 :(得分:0)
经过一些工作和一些额外的想法,我已经成功地使用Traits方法使代码工作,在&#34;我真正想要的内容&#34中所述;
简短摘要(我将复制下面的完整代码):
代码的Traits部分如下。有关完整代码,请参阅我的Github repository:
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);
};
}
这需要Generic_Factory
类中的新别名:
template <class AbstractType, class...ConstructorArgs>
class Generic_Factory{
using Pointer_T = typename core::Factory_Pointer_Traits<AbstractType>::pointer_t::type;
public:
/* ... */
};
当然,所有对旧模板模板参数Pointer_Type
的引用都会替换为新别名Pointer_T
。
在为我将拥有Factory的层次结构的根声明一个抽象类时,需要一个简单的别名或typedef:
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;
/* ... */
};
不幸的是,我无法找到一种简单的方法来摆脱宏的CLASS_NAME
参数。也许像boost :: make_shared_from_this和decltype
之类的东西可能会起作用......我不确定这是否值得付出努力。
我仍然希望听到您的任何建议或反馈。
谢谢和问候, 什穆埃尔