2012-05-01 3 views
0

Этот вопрос закрыт, потому что считается дубликатом:Заголовки, нуждающиеся друг друга

  1. C++ cyclical header dependency
  2. cyclic dependency between header files
  3. C++ error: 'Line2' has not been declared

Однако другой вопрос отличается от моего: они спросите другое дело, и ответ не работает с моей проблемой. Их ответ предполагает включить функцию в файл .cpp и определить класс перед объявлением. Я не могу поместить функцию в .cpp, потому что мой класс является шаблоном, и я уже определяю класс, но это не полезно.


У меня есть два файла заголовка a.h и b.h. В них определены два шаблонных класса A и B.

Функция A нужна работа с объектом B и наоборот. Поскольку они являются классами шаблонов, я не могу поместить функцию в файл .cpp, он должен оставаться в заголовке, и у меня большая головная боль из-за порядка включения.

Что такое хорошая методология для решения этой проблемы?

В настоящее время я перемещаю определение функции и нахожу способ включения заголовков в правильном порядке, но это становится все более сложным. Более того, мне не нравится иметь определение функции далеко от объявления класса (например, в другом файле).


Пример кода:

хиджры

#ifndef A_H 
#define A_H 

#include <iostream> 
#include "b.h" 
template< typename T > class B; 

template< typename T > 
class A { 
public: 
    B<void> *b; 
    void f(); 
    void g(); 
}; 
template< typename T > void A<T>::f() { 
    std::cout << "A::f" << std::endl; 
    b->f(); 
} 
template< typename T > void A<T>::g() { 
    std::cout << "A::g" << std::endl; 
} 

#endif 

b.h

#ifndef B_H 
#define B_H 

#include <iostream> 
#include "a.h" 
template< typename T > class A; 

template< typename T > 
class B { 
public: 
    A<void> *a; 
    void f(); 
    void g(); 
}; 
template< typename T > void B<T>::f() { 
    std::cout << "B::f" << std::endl; 
} 
template< typename T > void B<T>::g() { 
    std::cout << "B::g" << std::endl; 
    a->g(); 
} 

#endif 

main.cpp

#include "a.h" 
#include "b.h" 
int main() { 
    A<void> a; 
    B<void> b; 
    a.b = &b; 
    b.a = &a; 

    a.f(); 
    b.g(); 

    return 0; 
} 

Это не работает, потому что a.h включает b.h. b.h тогда не может включать a.h и таким образом B::g является ошибкой.

Для этого примера кода я могу перемещать B::g в main.cpp или в конце a.h, но с более сложной программой это непросто.

+0

http://stackoverflow.com/questions/5239943/c-cyclical-header-dependency http://stackoverflow.com/questions/2089056/циклическая зависимость между заголовками-файлами http://stackoverflow.com/questions/5058363/c-error-line2-has-not-been-declared/5058627#5058627 <- Dupes –

+0

Показать нас некоторый ** минимальный ** код, к сожалению, нет возможности сократить это. –

+0

@BillyNeal: нет, мой случай отличается от моего класса шаблоном: я не могу поместить объявление функции в исходный файл, а также объявить класс ('class A;') не решить мою проблему. –

ответ

1

Собственно, ваш код компилируется как-на моем Visual C++. Причина в том, что компилятор не выглядит «внутри» функции до тех пор, пока она не будет вызвана, то есть до main.cpp в вашем случае.

Откровенно говоря, я не уверен, что это гарантировано стандартом.В случае, если это не так, вы всегда можете разделить ваши заголовки на "независимые" и "зависимые" части, как это:

a_forward.h

#ifndef A_FORWARD_H 
#define A_FORWARD_H 

template< typename T > class B; 

template< typename T > 
class A { 
public: 
    B<T> *b; 
    void f(); 
    void g(); 
}; 

#endif 

ах

#ifndef A_H 
#define A_H 

#include <iostream> 
#include "a_forward.h" 
#include "b_forward.h" 

template< typename T > void A<T>::f() { 
    std::cout << "A::f" << std::endl; 
    b->f(); 
} 

template< typename T > void A<T>::g() { 
    std::cout << "A::g" << std::endl; 
} 

#endif 

b_forward.h

#ifndef B_FORWARD_H 
#define B_FORWARD_H 

template< typename T > class A; 

template< typename T > 
class B { 
public: 
    A<T> *a; 
    void f(); 
    void g(); 
}; 

#endif 

ЬН

#ifndef B_H 
#define B_H 

#include <iostream> 
#include "a_forward.h" 
#include "b_forward.h" 

template< typename T > void B<T>::f() { 
    std::cout << "B::f" << std::endl; 
} 

template< typename T > void B<T>::g() { 
    std::cout << "B::g" << std::endl; 
    a->g(); 
} 

#endif 

main.cpp

---||--- 
+0

«Честно говоря, я не уверен, что это гарантировано стандартом». Я уверен. **Это не**. На самом деле все наоборот: двухфазный поиск требует выполнения хотя бы некоторой проверки на первом проходе. Теперь он не может создать экземпляр шаблона на первом проходе, поэтому вполне возможно, что он будет компилироваться на совместимом компиляторе. Но вы не можете полагаться на компилятор, чтобы просмотреть превью-версию шаблона игнорирования. –

Смежные вопросы