Устранить циклическую зависимость шаблона C ++ - PullRequest
2 голосов
/ 17 февраля 2012

Предположим, у меня есть:

template<typename T>
class A { 
  typedef T t_type;
  void done_work();
};

template<typename T>
class B { 
  typedef T t_type;
  void do_work(){
    // adds work to an asynchronous event queue, eventually T.done_work() is called
  }
};

template<typename T>
class C { 
  typedef T t_type;
  void do_work(){
    // adds work to an asynchronous event queue, eventually T.done_work() is called
  }
};

typedef A<B<A > > a_with_b;
typedef A<C<A > > a_with_C;

void main(int argc, char** argv){
  a_with_b awb;
  a_with_c awc;
}

Как мне разрешить typedef a_with_b ?

Я хочу сделать это, потому что A имеет обратный вызов B, а B имеет обратный вызов A. Например, A вызовет B.do_work (), и в конечном итоге B вызовет A.done_work (). Более того, каждый из них является асинхронным вызовом, поэтому я не могу просто вызвать B.do_work () и подождать, пока B не вернет «выполнено», потому что у А в это время есть другая важная работа.

Причина, по которой я не могу просто сделать так, чтобы A ссылалась на B, заключается в том, что могут быть другие реализации, которые заменяют B, такие как C.

Ответы [ 3 ]

2 голосов
/ 17 февраля 2012

Я хочу сделать это, потому что A имеет обратный вызов B, а B имеет обратный вызов A. Например, A вызовет B.do_work (), и в конечном итоге B вызовет A.done_work ().

В идеале вы должны избегать взаимозависимостей, например ::10000

template<class T> struct A {
    std::function<void (T)> handler;
    void f(T) {}
    void work() { handler(T()); }
};
template<class T> struct B {
    std::function<void (T)> fn;
    void f(T) {}
    void work() { handler(T()); }
};

// ..
A<int> a;
B<int> b;
a.handler = std::bind(&B::f, &b);
b.handler = std::bind(&A::f, &a);
2 голосов
/ 28 ноября 2017

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

Использовать параметр шаблона шаблона для определения A:

template<template<typename> typename T>
class A { 
  typedef T<A> t_type;
  void done_work();
};

template<typename T>
class B { 
  typedef T t_type;
  void do_work(){
    // adds work to an asynchronous event queue, eventually T.done_work() is called
  }
};

template<typename T>
class C { 
  typedef T t_type;
  void do_work(){
    // adds work to an asynchronous event queue, eventually T.done_work() is called
  }
};

typedef A<B> a_with_b;
typedef A<C> a_with_c;

int main(int argc, char** argv){
  a_with_b awb;
  a_with_c awc;
}

Обратите внимание, что есть только несколько изменений.Теперь A принимает шаблон вместо типа .

Также обратите внимание, что B и C не изменились.

1 голос
/ 17 февраля 2012

Вы не можете.

По крайней мере, один из них не должен быть шаблоном в вашем случае.

Вы уверены, что вам нужен шаблон в этом случае?Если два класса A и B или A и C настолько тесно связаны, что один явно ссылается на другой, то вполне очевидно, что шаблоны не должны использоваться в классах B и C, потому что вы не могли бы специализировать какой-либо из этих классов чем-либоиначе, не нарушая всю магию обратного вызова.

Кстати, библиотека обратного вызова, такая как sigc ++, может быть тем, что вам нужно.

...