C ++ createObject()工厂

时间:2013-01-01 20:03:37

标签: c++ templates boost-mpl

我想用简单的C ++语法创建一个简单的工厂方法:

void *createObject(const char *str,...)
{
  if(!strcmp("X",str))
     return new X(...);
}

我无法弄清楚这个的语法。我一直在看模板元编程并使用mpl :: vectors,但我不知道如何传递这种语法。我希望尽可能避免使用C va_lists,并采用如上所述的干净语法。

4 个答案:

答案 0 :(得分:8)

这是 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 类型调用此函数。

  • 它返回shared_ptr<void>而不是普通void*。这允许您在工厂内控制一旦所有对它的引用都消失后应该如何清理对象。用户无需知道或关心他是否应该从您的工厂调用标准deletedeleteObject方法。

更新:对于那些提示unique_ptr的人,您可以阅读here,了解shared_ptr带来的可能性。只返回指向new分配对象的指针的受限制工厂可以而且应该使用unique_ptr

答案 1 :(得分:0)

除了如何使用漂亮的C ++ 11可变参数模板创建对象的代码(如K-ballo的答案所示),这个答案显示了我将如何处理 a项目中的一组类。这个方法很大,只有在你知道自己在做什么的情况下才会推荐,但是,在为项目添加新类时,你只需将它们添加到列出所有类的单个文件中,所以如果项目变得庞大,它有助于保持概述。

如果必须多次列出类,请使用此方法 ,例如,如果您还想拥有std::string className()函数,例如,返回类的名称不使用C ++运行时类型信息。需要列出项目中所有类的每个此类函数都可以采用与以下类似的方式实现。

<强> classes.h

/* For every class in your project which should be creatable through your
 * factory, add a line here. */
CLASS(Foo)
CLASS(Bar)
CLASS(Baz)

<强> factory.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;
}

答案 2 :(得分:0)

如果你不能使用可变参数模板,并且不希望使用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程序选项。

答案 3 :(得分:0)

我最终使用的解决方案是使用模板参数创建0,N个单例。 N = 8时效果很好。有点难看,但只需要做一次。