шаблоны — C ++ createObject () Factory

Я хотел бы создать простой метод фабрики с простым синтаксисом C ++:

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

Я не могу понять синтаксис для этого. Я смотрел на метапрограммирование шаблонов и использовал mpl :: vectors, но я не уверен, как передать этот синтаксис. Я действительно хочу по возможности избегать использования C va_lists и использовать чистый синтаксис, подобный приведенному выше.

2

Решение

Это было бы лучшим подходом к 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*, Это позволяет вам контролировать изнутри фабрики, как объект должен быть очищен после того, как все ссылки на него исчезнут. Пользователю не нужно знать или заботиться, должен ли он называть стандарт deleteили, может быть, deleteObject метод с вашего завода.

Обновить: Для тех, кто предлагает unique_ptr, ты можешь читать Вот о возможностях, которые shared_ptr приносит на стол. Ограниченная фабрика, которая возвращает только указатели на newВыделенные объекты могут и должны использовать unique_ptr,

8

Другие решения

В дополнение к коду на как создавать объекты, используя красивые шаблоны C ++ 11 variadic (как видно из ответа К-Балла), этот ответ показывает, как бы я справился набор классов в проекте. Этот метод очень полезен и рекомендуется только в том случае, если вы знаете, что делаете, однако при добавлении новых классов в ваш проект вам нужно всего лишь добавить их в один файл, в котором перечислены все ваши классы, поэтому, если проект становится огромным, это помогает держать обзор.

Используйте этот подход только, если вам нужно перечислить ваши классы несколько раз, например, если вы также хотите иметь 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;
}
0

если ты не может использовать вариадические шаблоны и не хочу чтобы использовать varargs в стиле 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

В итоге я решил создать 0, N синглетонов с шаблонными параметрами. Это работает довольно хорошо с N = 8. Немного некрасиво, но это нужно сделать только один раз.

0