我想用简单的 C++ 语法创建一个简单的工厂方法:
void *createObject(const char *str,...)
{
if(!strcmp("X",str))
return new X(...);
}
我无法弄清楚这个的语法。我一直在研究模板元编程并使用 mpl::vectors,但我不确定如何传递这种语法。如果可能的话,我想真正避免使用 C va_lists 并使用像上面那样的干净语法。
这将是C++11的更好方法:
template< typename ...Args >
std::shared_ptr<void> createObject( std::string const& name, Args&& ...args )
{
if( name == "X" )
{
return try_make_shared< X >( std::forward< Args >( args )... );
}
/* other cases here*/
return nullptr;
}
template< typename T, typename ...Args >
typename std::enable_if<
std::is_constructible< T, Args >::value
, std::shared_ptr< T >
>::type try_make_shared( Args&&... args )
{
return std::make_shared< X >( std::forward< Args >( args )... );
}
template< typename T, typename ...Args >
typename std::enable_if<
!std::is_constructible< T, Args >::value
, std::shared_ptr< T >
>::type try_make_shared( Args&&... args )
{
throw std::invalid_argument( "The type is not constructible from the supplied arguments" );
return nullptr;
}
与您的代码的区别是
它使用可变参数模板函数而不是省略号参数,因此参数的数量和类型在编译时仍然可用(您不会放松类型检查)。此外,您可以使用非 POD类型调用此函数。
它返回 ashared_ptr<void>
而不是 plain void*
。这使您可以在工厂内控制对象的所有引用都消失后应该如何清理它。用户不需要知道或关心他是否应该调用标准delete
,或者可能是deleteObject
您工厂的方法。
更新:对于那些建议的人unique_ptr
,您可以在此处shared_ptr
阅读 a带来的可能性。只返回指向new
-ly 分配对象的指针的受限工厂可以并且应该使用unique_ptr
.
除了有关如何使用漂亮的 C++11 可变参数模板创建对象的代码(如 K-ballo 的答案中所见)之外,此答案还显示了我将如何处理项目中的一组类。这种方法是一个大技巧,只有在您知道自己在做什么时才推荐使用,但是,在向项目添加新类时,您只需将它们添加到列出所有类的单个文件中,因此如果项目变得庞大,它有助于保持概览。
仅在必须多次列出类时使用这种方法,例如,如果您还想要一个std::string className()
函数,例如,在不使用 C++ 运行时类型信息的情况下返回类的名称。需要列出项目中所有类的每个此类功能都可以以与以下类似的方式实现。
类.h
/* For every class in your project which should be creatable through your
* factory, add a line here. */
CLASS(Foo)
CLASS(Bar)
CLASS(Baz)
工厂.cpp
template< typename ...Args >
std::shared_ptr<void> createObject( std::string const& name, Args&& ...args )
{
// Define what code to insert for every class:
#define CLASS(T) \
else if(name == #T) \
return std::make_shared<T>(std::forward(args)...);
// List all cases:
if(0) /*do nothing*/; // <-- needed because the macro uses else if
#include "classes.h"
#undef CLASS
return nullptr;
}
如果您不能使用可变参数模板,并且不想使用 C 风格的可变参数,那么您唯一的选择是为参数提供一些通用表示。
boost::shared_ptr<void> createObject(const char *str,
int argc, const char *argv[])
{
if(!strcmp("X",str))
return new X(argc, argv);
if(!strcmp("Y",str))
return make_Y(argc, argv);
}
如上所示Y
,将参数处理拆分为工厂函数而不是将构造函数耦合到选项格式可能是明智的。例如,您可能想要切换到属性映射或 Boost 程序选项。
我最终使用的解决方案是使用模板化参数创建 0、N 个单例。它在 N = 8 时工作得很好。有点难看,但只需要完成一次。