Как сохранить или переслать тип класса шаблона CRTP - PullRequest
3 голосов
/ 15 ноября 2011

Общая идея: Пара классов, менеджер, который создает рабочих. Каждый принимает набор политик, которые настраивают поведение. Каждая политика имеет часть, которая влияет на менеджера (выполняет некоторую настройку) и часть, которая влияет на работника (добавляет определенные рабочие функции, которые необходимо вызывать и вызывать из функций в классе рабочего хоста - в настоящее время выполняется через CRTP)

Политики, используемые в работнике, всегда будут отражать политики в менеджере. Т.е. manager<foo,bar> создаст рабочие типа worker<foo_worker,bar_worker>. Из-за этого я хочу сохранить тип рабочей политики в политике менеджера, чтобы конечному пользователю не приходилось указывать оба.

Следующий код реализует упрощенную версию моего кода, которая демонстрирует проблему. Посмотрите на комментарии класса менеджера. В настоящее время (для того, чтобы пример скомпилировался) менеджер делает работников жестко запрограммированного типа.

Вопрос: Как записать тип класса шаблона foo_worker в классе foo таким образом, чтобы менеджер мог определить / найти правильный рабочий класс на основе своих собственных параметров шаблона?

typedef foo_worker work_policy; внутри class foo не работает, потому что foo_worker не является шаблоном класса. Я безуспешно пробовал разные виды классов-обёрток и комбинации типов и шаблонов. Я также пытался использовать foo_worker как вложенный класс в foo.

Я бы предпочел не требовать C ++ 11, если смогу избежать этого, но хотел бы рассмотреть это, если это радикально упростит эту проблему.

Есть ли другой способ структурирования подобной системы, позволяющий избежать этой проблемы?

Заранее спасибо =)

#include <iostream>

// Example policy1 "foo"
template <typename worker_type> 
class foo_worker {
public:
    void policy_work() {
        std::cout << "foo_worker specific work" << std::endl;
        static_cast<worker_type*>(this)->work_finish();
    }
};

class foo {
public:
    foo() {
        std::cout << "foo setup" << std::endl;
    }
};

// Example policy2 "bar"
template <typename worker_type> 
class bar_worker {
public:
    void policy_work() {
        std::cout << "bar_worker specific work" << std::endl;
        static_cast<worker_type*>(this)->work_finish();
    }
};

class bar {
public:
    bar() {
        std::cout << "bar setup" << std::endl;
    }
};

// worker class
template <template <class> class policy1,template <class> class policy2>
class worker 
  : public policy1< worker<policy1,policy2> >,
    public policy2< worker<policy1,policy2> >
{
public:
    typedef policy1< worker<policy1,policy2> > policy1_type;
    typedef policy2< worker<policy1,policy2> > policy2_type;

    void work() {
        std::cout << "start work" << std::endl;
        static_cast<policy1_type*>(this)->policy_work();
        static_cast<policy2_type*>(this)->policy_work();
    }
    void work_finish() {
        std::cout << "finish work" << std::endl;
    }
};

// manager class
template <typename policy1,typename policy2>
class manager : public policy1, public policy2 {
public:
    // this line hard codes workers to the foo_worker and bar_worker policy. 
    // I want to be able to look up which policies to send the worker based 
    // on the policies that was given to the manager.
    typedef worker<bar_worker,foo_worker> worker_type; 

    // Would like to be able to do something like this instead:
    //typedef worker<policy1::work_policy,policy2::work_policy> worker_type;

    manager() : policy1(),policy2() {
        std::cout << "manager setup" << std::endl;
    }

    worker_type* create() {
        return new worker_type();
    }
};

int main() {
    manager<foo,bar> m;
    manager<foo,bar>::worker_type* w = m.create();

    w->work();

    return 0;
}

1 Ответ

0 голосов
/ 22 ноября 2011

Может быть, вы можете что-то придумать, используя что-то вроде черт типа?Надеюсь, я вас правильно понял, так что вы думаете о чем-то вроде:

template<typename PolicyType>
struct worker_type
{
};

template<>
struct worker_type<foo>
{
    typedef foo_worker type;
};

// .... etc ...

//...

template<typename p1, typename p2>
class manager : public p1, public p2
{
    public:
        typedef worker< typename worker_type<p1>::type,
                        typename worker_type<p2>::type > worker_type;
// ...
...