Класс шаблона С++, ссылающийся на самого себя

Мне нужно создать архитектуру MVC, в которой классы View и Controller уже написаны в виде шаблонов следующим образом:

template<class Model, class View>
class Controller { /* Implement Controller */ };

template<class Model, class Controller>
class View { /* Implement View */ };

У меня также есть класс модели:

class Model { /* Implement Model */ };

Я не могу контролировать, как создаются классы Model, View и Controller. Теперь, как мне создать экземпляр контроллера или представления?

Чтобы лучше объяснить ситуацию, если я хочу создать контроллер, используя приведенные выше классы View и Model (мне НЕ разрешено использовать какие-либо другие классы), я получаю:

ПРИМЕЧАНИЕ. Далее следует недопустимый код C++.

Controller< Model, View< Model, // ad infinitum

тогда как следующее также неверно:

ПРИМЕЧАНИЕ. Далее следует недопустимый код C++.

Controller< Model, View< Model, Controller > > c;

person v vv cvvcv    schedule 06.04.2014    source источник
comment
Как создать экземпляр любого класса C++? Возможно, вы захотите переосмыслить то, что вы просите, потому что это настолько туманно, насколько это может быть как есть (и единственное, что удаленно допустимо в C++, это Model; и в шаблонах контроллера, и в шаблонах представления отсутствуют параметры шаблона, которые я Я почти уверен, что это будет иметь отношение к этому).   -  person WhozCraig    schedule 06.04.2014
comment
А что не так с самореференцией?   -  person blackbird    schedule 06.04.2014
comment
Не могли бы вы привести пример реального кода компиляции? Код, который вы показываете, даже не является допустимым C++.   -  person Jens    schedule 06.04.2014
comment
меньше, чем не удалось спасти @jww спасибо   -  person laune    schedule 06.04.2014
comment
Извините, но я не понимаю, как это недопустимый код C++? Не могли бы вы объяснить проблему, пожалуйста?   -  person v vv cvvcv    schedule 06.04.2014
comment
@WhozCraig - Причина, по которой я задал вопрос, заключается в том, что я чувствовал, что это туманно.   -  person v vv cvvcv    schedule 06.04.2014
comment
@blackbird - если я хочу создать экземпляр класса View выше с классом Controller, я сталкиваюсь с циклическим циклом.   -  person v vv cvvcv    schedule 06.04.2014
comment
@Jens - То, что я набрал выше, компилируется для меня, то, что я хочу сделать, не компилируется, отсюда и вопрос.   -  person v vv cvvcv    schedule 06.04.2014
comment
Итак, что вы хотите сделать? Не могли бы вы опубликовать код, который не компилируется? Классы, которые вы там разместили, могут быть созданы как Controller<int,int> c; View<int, int> v; Model m;. Не думайте, что это то, чего вы хотите.   -  person Jens    schedule 06.04.2014
comment
@Jens - обновил вопрос с неверным кодом.   -  person v vv cvvcv    schedule 06.04.2014
comment
Я предполагаю, что вам нужно создать свои собственные классы, возможно, используя классы-шаблоны или наследуя их. Затем создайте свои собственные классы.   -  person Jens    schedule 06.04.2014
comment
Если я это понимаю, и это большое если, мне кажется, что разработчики хотят иметь иерархию наследования, которая может использовать оба шаблона для универсальной реализации, но один из них (не имеет значения, какой) < i>должен быть конечным; тогда последний определяется в терминах первого. По иронии судьбы, не имеет значения, какой был выбран. Я должен спросить. Какой сумасшедший собрал это без лучшего объяснения использования?   -  person WhozCraig    schedule 06.04.2014
comment
@WhozCraig - не нужно быть сумасшедшим, чтобы создать это. Только представьте, что вы используете библиотеки от двух разных поставщиков и заставляете их работать вместе.   -  person v vv cvvcv    schedule 06.04.2014
comment
Это не то же самое. Библиотеки должны были бы зависеть друг от друга еще до того, как вы подошли бы к столу. И библиотеки зависимы при использовании, а не при определении, как эти шаблоны. Это действительно должен быть сумасшедший. У меня есть вариант использования, который, как я думаю, работает с этим, но интуиция далеко не ясна. Если смогу формализовать, то выложу.   -  person WhozCraig    schedule 06.04.2014


Ответы (3)


Это возможная реализация

template<typename View, typename Model>
struct Controller {
    View *view;
    Model *model;

    Controller() : view(0), model(0) {}
    void setUp(View *v, Model *m) {
        view = v;
        model = m;
    }

    virtual void change() = 0;
};

template<typename Controller, typename Model>
struct View {
    Controller *controller;
    Model *model;

    View() : controller(0), model(0) {}
    void setUp(Controller *c, Model *m) {
        controller = &c;
        model = &m;
    }

    virtual void display() = 0;
};

Чтобы создать экземпляр, хитрость заключается в том, чтобы получить класс из шаблона, который имеет предварительно объявленный класс в качестве параметра:

struct MyModel {
    int x;
    MyModel(int x) : x(x) {}
};

struct MyController;
struct MyView : View<MyController, MyModel>
{
    void display() { std::cout << model->x << std::endl; }
};

struct MyController : Controller<MyView, MyModel>
{
    void change() { model->x = 44; }
};

После этого вы можете создавать экземпляры и настраивать их

int main(int argc, const char *argv[]) {
    MyModel m(42);
    MyView v;
    MyController c;
    v.setUp(&c, &m); c.setUp(&v, &m);

    v.display();
    c.change();
    v.display();

    return 0;
}
person 6502    schedule 06.04.2014
comment
Большое спасибо. Это работает для меня. Я бы проголосовал за вас, но у меня нет необходимого представителя. - person v vv cvvcv; 06.04.2014
comment
+1 Это очень близко к тому, что я собрал воедино, ссылку на который я приведу здесь . я не делал лишних усилий для функционального образца, только для настройки. Просто рад, что я был не единственным, кто видел что-то подобное. - person WhozCraig; 06.04.2014

Это компилируется:

class MyView;
class MyController: public Controller<Model,MyView>{};
class MyView: public View<Model,MyController>{};
MyController myC;
MyView myV;

Но это зависит от того, как написаны Controller и/или View. MyView является неполным на момент создания MyController, поэтому можно использовать только указатели.

person laune    schedule 06.04.2014
comment
Вау, это действительно компилируется! Вы можете использовать предварительно объявленные классы в качестве аргументов шаблона при написании определения класса? Для меня это новое знание! Я написал несколько фиктивных функций в Controller и View и вызвал функцию View из Controller - она ​​работает!!! - person v vv cvvcv; 06.04.2014
comment
Извините, я отметил ответ @ 6502 как правильный, потому что он гораздо более подробный. Но то, что вы говорите, верно. Я бы проголосовал за вас, но, к сожалению, у меня нет необходимых представителей. Большое спасибо за вашу помощь. - person v vv cvvcv; 06.04.2014
comment
@vvvcvvcv он компилируется, потому что в реальных классах MyController и MyView нет никакого использования объектов. Все идет наперекосяк, если только все не будет тщательно настроено как ссылки и/или указатели. - person WhozCraig; 06.04.2014
comment
@WhozCraig Надо полагать, что дизайнер этой пары знал, что делал. В своем ответе я предупреждал: только View * в Controller! - person laune; 06.04.2014

Ты не сможешь это сделать. Несколько мыслей, которые помогут вам двигаться дальше:

  • Используйте шаблоны только для определенных функций-членов

    Если вам в классах не нужно хранить элементы данных, вы можете написать:

    template<class Model>
    class Controller {
    public:
        void foo() // does not need View
        { ... }
    
        template<typename View>
        void bar(const View& v) // works with a specific View
        { ... }
    };    
    
  • Возможно, Controller не нужно знать View?

    template<class Model> // no dependency on View
    class Controller { /* Implement Controller */ };   
    template<class Model, class Controller>
    class View { /* Implement View */ };
    // no it works
    Controller<MyModel> ctrl;
    View<MyModel, Controller<MyModel>> view;
    
  • Используйте интерфейс:

    class IController { ... };
    class IView { ... };
    template<class Model>
    class Controller : public IController { /* Implement Controller */ };   
    template<class Model>
    class View : public IView { /* Implement View */ };
    
  • Получайте типы из ваших типов шаблонов:

    class MyView;
    class MyController : public Controller<MyModel,MyView> { };
    class MyView : public View<MyModel,MyController> { };
    

    Здесь вы должны помнить об этой проблеме: Два шаблона классы, состоящие из членов друг друга

person Danvil    schedule 06.04.2014
comment
Вы имеете в виду разработчиков C++? Это не ошибка, просто так работают шаблоны. - person Danvil; 06.04.2014
comment
Удалил мои предыдущие комментарии после дальнейшего обсуждения. Ваши решения работают косвенно, поэтому не голосуют за вас. - person v vv cvvcv; 06.04.2014