LINUX.ORG.RU

Произвольный порядок списка инициализации шаблона


1

2

У меня есть два типа понтейнера которые принимают по 3 шаблонных параметра

template<class T, class Deferred, class Deadline>
struct prio_container;

template<class T, class Deferred, class Deadline>
struct queue_container;
Тип T - это элемент контейнера.

Deferred и Deadline это плагины, которые расширяют функционал. Все делается без палиморфизма, исключительно на этапе компиляции (статический полиморфизм).

Я хочу абстрагироваться от конкретных реализаций и сделать интерфейс, который бы через указание шаблонных параметров выбирал нужную специализацию. Притом даже сам тип контейнера для пользователя выглядил бы как подключаемый плагин. А так же отвязаться от порядка задания параметром шаблона, и необходимости указывать их все, даже если они не используются. Вот пример того что я пытаюсь сделать.

template<class T, 
         class Plugin1 = disable_plugin,
         class Plugin2 = disable_plugin,
         class Plugin3 = disable_plugin>
struct container;

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

#include <iostream>
#include <string>

using namespace std;

#define static_type(name) \
    static const std::string& type() \
    { \
        static std::string type_(name); \
        return type_; \
    } \

struct prio_plugin;
struct dis_prio_plugin;

struct deferred_plugin
{ static_type("deferred"); };

struct deadline_plugin
{ static_type("deadline"); };

struct disable_plugin
{ static_type("disable"); };

template<class T, class Deferred, class Deadline>
struct prio_container
{
    static const std::string& type()
    {
        static std::string type_("prio_container<" + 
                                    Deferred::type() + ", " +
                                    Deadline::type() + ">");
        return type_;
    }
};

template<class T, class Deferred, class Deadline>
struct queue_container
{
    static const std::string& type()
    {
        static std::string type_("queue_container<" + 
                                    Deferred::type() + ", " +
                                    Deadline::type() + ">");
        return type_;
    }
};

template<class T, 
         class Plugin1 = disable_plugin,
         class Plugin2 = disable_plugin,
         class Plugin3 = disable_plugin>
struct container;

template<class T, 
         class Plugin1,
         class Plugin2>
struct container<T, prio_plugin, Plugin1, Plugin2>
{
    typedef prio_container<T, Plugin1, Plugin2> type;
};

template<class T, class DisableDeadline>
struct container<T, prio_plugin, deferred_plugin, DisableDeadline>
{
    typedef prio_container<T, deferred_plugin, DisableDeadline> type;
};

template<class T, class DisableDeferred>
struct container<T, prio_plugin, deadline_plugin, DisableDeferred>
{
    typedef prio_container<T, DisableDeferred, deadline_plugin> type;
};

template<class T>
struct container<T, prio_plugin, deadline_plugin, deferred_plugin>
{
    typedef prio_container<T, deferred_plugin, deadline_plugin> type;
};

template<class T>
struct container<T, prio_plugin, deferred_plugin, deadline_plugin>
{
    typedef prio_container<T, deferred_plugin, deadline_plugin> type;
};



int main()
{
   cout << "Hello World" << endl; 
   
   cout << container<int, prio_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deadline_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deferred_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deferred_plugin, deadline_plugin>::type::type() << std::endl;
   cout << container<int, prio_plugin, deadline_plugin, deferred_plugin>::type::type() << std::endl;
   
   return 0;
}
prio_container<disable, disable>
prio_container<disable, deadline>
prio_container<deferred, disable>
prio_container<deferred, deadline>
prio_container<deferred, deadline>


Пусть конкретные контейнеры принимают один супер-трейт-шаблон Configuration, который агрегирует в себе всю настраиваемую информацию:

template <typename T, class Configuration = DefaultConfiguration>
class container;
Когда container надо что-то настраиваемое, то он лезет в Configuration::foo.

Далее. Если C++03, то фигачишь список типов из плагинов. (Препроцессорные макросы по вкусу.) Если C++11, то уже есть class... Plugins. Потом делаешь шаблонный Builder, который рекурсивно по одному разбирает плагины и заполняет этот самый Configuration.

ilammy ★★★
()
Последнее исправление: ilammy (всего исправлений: 1)
Ответ на: комментарий от ilammy

Не совсем уловил мысль. На счет того, что контейнер должен принимать агрегированный «нечто» это понятно, но чем конкретно должно быть это Configuration? Структура?

struct DefaultConfiguration
{
  typedef disable_plugin deferred_plugin;
  typedef disable_plugin deadline_plugin;
};
Да, упрощает, но некрасиво. Я тут накидал прототипчик с использованием boost::mpl::set и у меня получилось, что аргументы шаблона могут перечисляться в любом порядке и в любом колличестве. Типо как initialize_list но без именования. Доведу до ума, и покажу.

Cupper
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.