0

This question is closed because it is considered a duplicate of:

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

However the other question are different from my: they ask a different case and the answer do not work with my problem. Their answer suggest to put the function into a .cpp file and to define the class before to declare it. I cannot put the function in .cpp because my class is a template, and I already define the class, but it is not useful.


I have two header file a.h and b.h. In they are defined two template class A and B.

A function of A need work with object of B and viceversa. Since they are template class, I can not put the function in .cpp file, it must stay in header, and I have a big headache because of the order of the inclusion.

What is a good methodology to solve this problem?

Currently I move function definition around and find a way to include the headers in the correct order, but this become always more complex. Moreover I do not like to have function definition far from class declaration (for example in other file).


Example code:

a.h

#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;
}

This not work because a.h include b.h. b.h then can not include a.h and thus B::g is error.

For this example code I can move B::g in main.cpp or at the end of a.h, but with more complex program this is not easy.

Community
  • 1
  • 1
  • http://stackoverflow.com/questions/5239943/c-cyclical-header-dependency http://stackoverflow.com/questions/2089056/cyclic-dependency-between-header-files http://stackoverflow.com/questions/5058363/c-error-line2-has-not-been-declared/5058627#5058627 <-- Dupes – Billy ONeal May 01 '12 at 07:54
  • Show us some **minimal** code, unfortunately there's no shortcut to solving this. – Luchian Grigore May 01 '12 at 07:54
  • @BillyONeal: no, my case is different because my class are template: I can not put the declaration of the function in source file, and also to declare the class (`class A;`) not solve my problem. – Ritardi Giuseppe May 01 '12 at 07:59
  • @RitardiGiuseppe: Why not? You can declare class templates just like you declare classes. – Billy ONeal May 02 '12 at 18:32

1 Answers1

1

Actually, your code compiles as-is on my Visual C++. The reason is that compiler does not look "inside" a function until it is actually called, i.e. until main.cpp in your case.

Frankly, I'm not sure if this is guaranteed by the standard. In case it isn't, you can always split your headers to "independent" and "dependent" portions, like this:

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

a.h

#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

b.h

#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

---||---
Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
  • "Frankly, I'm not sure if this is guaranteed by the standard." I'm sure. **It's not**. In fact it's quite the opposite: two-phase lookup requires doing at least some checking on the first pass. Now, it can't instantiate the template on the first pass, so it's possible that it will compile on a conformant compiler. But you can't rely on the compiler to look ignore template pre-instantiation. – Nicol Bolas May 01 '12 at 09:54