I have two non-template classes, A and A::nested, and a class template, B.
I have a problem where a templated method in class A (A_method), defined in a .tpp file (A.tpp), requires the definition of class B since it tries to modify a member of class B inside it.
At the same time, a method in class B requires the definition of class A since one of its parameters is a class nested inside class A (A::nested).
The specific error is:
error: invalid use of incomplete type 'class B<>'
I have traced this problem to have arisen from the compilation of B.cpp, where it then #includes B.hpp, which #includes A.hpp, which #includes A.tpp, which #includes B.hpp again.
I have included the files below, they are all short and below 30 lines. Thank you.
types.hpp (just an empty class holder for significance)
#ifndef TYPES
#define TYPES
class defaulttype {};
class argtype {};
class alttype {};
#endif // TYPES
A.hpp
#ifndef A_HEADER
#define A_HEADER
#include "types.hpp"
template<typename = defaulttype>
class B;
class A
{
public:
template<typename...>
class nested{};
B<>* data_member;
B<alttype>* const second_data_member;
template<typename Type>
void A_method(B<Type>);
A();
};
#include "A.tpp" //".tpp" is the extension I am using to indicate
//template source files, other places may use ".tcc" or ".ipp"
#endif //A_HEADER
A.tpp
#ifndef A_TPP
#define A_TPP
#include "B.hpp"
#include <iostream>
template<typename T>
void A::A_method(B<T> object)
{
data_member->next = &object;
std::cout << object.name;
}
#endif // A_TPP
A.cpp
#include "A.hpp"
A::A()
:second_data_member(new B<alttype>)
{}
B.hpp
#ifndef B_HEADER
#define B_HEADER
#include "A.hpp"
#include "types.hpp"
#include <iostream>
//default arg is defaulttype, previously forward declared as such in A.hpp
template<typename T>
class B
{
public:
B* next;
};
template<>
class B<argtype> : public B<>
{
public:
std::string name;
template<typename...argpack>
void B_func_requires_nested(A::nested<argpack...>);
};
#include "B.tpp"
#endif //B_HEADER
B.tpp
#ifndef B_TPP
#define B_TPP
template<typename...argpack>
void B<argtype>::B_func_requires_nested(A::nested<argpack...> object)
{}
#endif // B_TPP
B.cpp
#include "B.hpp"
Thank you for the help.
Related
Well I have 2 classes in 2 header and 2 cpp files
#class1.h
#ifndef class1_h
#define class1_h
class myclass;
#endif
#class2.h
#ifndef class2_h
#define class2_h
class anotherclass;
#endif
#class1.cpp
class myclass
{
anotherclass test1;
}
#class2.cpp
class anotherclass
{
myclass test2;
}
And of course a simple main
Well I think it's obvious why this thing wont even compile
my question here is how to make it compile?
Having the classes in different files is mandatory..
If the class definitions (the bodies that is) must be in separate files then the members of the declared type can only be a pointer (or a reference but that is unusual). You would then need a function in the source file where the class is actually defined that returns a pointer-to-instance of the type.
MyClass.h:
#if !defined(MYCLASS_H)
#define MYCLASS_H
class MyClass;
MyClass * CreateMyClass();
#endif
OtherClass.h:
#if !defined(OTHERCLASS_H)
#define OTHERCLASS_H
class OtherClass;
OtherClass * CreateOther();
#endif
myclass.cpp
#include "otherclass.h"
class MyClass
{
OtherClass * ptrOther;
public:
MyClass()
: ptrOther(CreateOther())
{}
};
otherclass.cpp:
#include "myclass.h"
class OtherClass
{
MyClass * ptrMyClass;
public:
OtherClass()
: ptrMyClass(CreateMyClass())
{}
};
Note that doing things this way you would not actually be able to do anything with ptrOther or ptrMyClass ((possibly not even free them correctly), It would be much more typical to place the class definitions in the header and separate out the member definitions (for functions and statics), like the following:
MyClass2.h:
#if !defined(MYCLASS2_H)
#define MYCLASS2_H
#include "OtherClass.h"
class MyClass2
{
OtherClass * ptrOther;
public:
MyClass2();
};
#endif
cMyClass.cpp:
#include "MyClass2.h"
MyClass2::MyClass2()
: ptrOther(CreateOther())
{}
Header files define class interfaces. Source code '.cpp' files are using for the implementation. Your source code has the implementation and the class interface.
#ifndef CLASSB
#define CLASSB
#include "ClassA.h"
namespace name {
class ClassB
{
public:
static Handle conn();
};
}
#endif
-
#include "ClassB.h"
Handle name::ClassB::conn()
{
return getHandle(ClassA::it().str());
}
-
#ifndef CLASSA
#define CLASSA
#include "ClassB.h"
namespace name {
class ClassA
{
public:
template <typename T>
T myFunc(const std::string&)
{
auto tmp = ClassB::conn();
}
};
}
#endif
Calling ClassB::conn() gives a compiler error which says that the class ClassB is not declared. When I forward declare it I get an error message about an incomplete type.
I can't move the template function to my .cpp files as it is a template function. So, how to fix this?
Just remove #include "ClassA.h" from class B's header and it should work. But there appear to be multiple compilation problems with your code so it's hard to say (missing function getHandle, missing it(), missing type Handle etc).
This question already has answers here:
Resolve build errors due to circular dependency amongst classes
(12 answers)
Closed 9 years ago.
At first I am apologize for a slightly longer code... There are 3 classes A,B,C
A.h
#ifndef A_H
#define A_H
template <typename T>
class C;
class A
{
public:
template <typename T>
static void testa ( T b);
};
#include "A.hpp"
#endif
A.hpp
#ifndef A_HPP
#define A_HPP
#include "C.h"
#include "B.h"
template <typename T>
void A::testa ( T a)
{
B::testb( a );
}
#endif
B.h
#ifndef B_H
#define B_H
class B
{
public:
template <typename T>
static void testb ( T b );
};
#include "B.hpp"
#endif
B.hpp
#ifndef B_HPP
#define B_HPP
#include "C.h"
template <typename T>
void B::testb ( T b )
{
C <T>::test(b, e1 ); //Error
}
#endif
C.h
#ifndef C_H
#define C_H
#include "A.h"
typedef enum
{
e1=1, e2,
} TEnum;
template <typename T>
class C
{
public:
static void test (T c, const TEnum t) {}
};
#endif
main.cpp
#include "A.h"
using namespace std;
int main()
{
double x = 1.0;
A::testa(x);
return 0;
}
Due to the possible circular dependency (my estimation), when the code is a part of the library, the following eeror occurs:
C <T>::test(b, e1 ); |261|error: 'e1' was not declared in this scope|.
However, extracting the code to the example, the error can not be reproduced.
The VS2012 compiler works well in both cases...
I do not, how to fix such a type of the problem? Is it a good way to use extern?
It is clear that it is difficult to advise; especially, when the error can not be reproduced...
Thanks for your help...
Have you tried putting classes A, B, and C into a single namespace, and then declaring your enum inside the namespace itself? I'm not sure if this would resolve your problem but it may help clear up some circular dependencies.
Also it would appear that A is not in fact dependent on C, so you should remove the line #include C.h' from A.hpp and, in main.cpp, include C.h instead of A.h.
Hope this helps.
I am trying to implement an observer pattern with a template subject class. The observers don't (need to) know the subjects type, so I made an interface for the attach method without this type. This is my implementation:
SubjectInterface.h
#ifndef SUBJECTINTERFACE_H_
#define SUBJECTINTERFACE_H_
#include <list>
#include "Observer.h"
// Template-independant interface for registering observers
class SubjectInterface
{
public:
virtual void Attach(Observer*) = 0;
}; // class SubjectInterface
#endif // SUBJECTINTERFACE_H_
Subject.h
#ifndef SUBJECT_H_
#define SUBJECT_H_
#include <list>
#include "Observer.h"
#include "SubjectInterface.h"
template <class T>
class Subject : public SubjectInterface
{
public:
Subject();
~Subject();
void Attach(Observer*);
private:
T mValue;
std::list<Observer*> mObservers;
}; // class Subject
#include "Subject.cpp"
#endif // SUBJECT_H_
Subject.cpp
template <class T>
Subject<T>::Subject()
{
}
template <class T>
Subject<T>::~Subject()
{
}
template <class T>
void Subject<T>::Attach(Observer* test)
{
mObservers.push_back(test);
}
Observer.h
#ifndef OBSERVER_H_
#define OBSERVER_H_
#include "SubjectInterface.h"
#include <iostream>
class Observer
{
public:
Observer(SubjectInterface* Master);
virtual ~Observer();
private:
SubjectInterface* mMaster;
}; // class Observer
#endif // OBSERVER_H_
Observer.cpp
#include "Observer.h" // include header file
Observer::Observer(SubjectInterface* Master)
{
Master->Attach(this);
}
Observer::~Observer()
{
}
When I compile this using the gcc 4.3.4, I get the following error message:
SubjectInterface.h:10: error: ‘Observer’ has not been declared
I don't understand this, because the Observer is included just a few lines above. When I change the pointer type from Observer* to int*, it compiles OK. I assume that there is a problem with the template subject and the non-template interface to it, but that is not what gcc is telling me and that doesn't seem to be the problem when using int*.
I searched for template/observer, but what I found (e.g. Implementing a Subject/Observer pattern with templates) is not quite what I need.
Can anyone tell me, what I did wrong or how I can call the templated attach-method from a non-template observer?
You have a circular include chain, SubjectInterface.h includes Observer.h which in turns includes SubjectInterface.h.
This means that the include guards will prevent Observer from being visible. To fix it instead forward declare Observer.
// SubjectInterface.h
#ifndef SUBJECTINTERFACE_H_
#define SUBJECTINTERFACE_H_
#include <list>
class Observer; //Forward declaration
// Template-independant interface for registering observers
class SubjectInterface
{
public:
virtual void Attach(Observer*) = 0;
}; // class SubjectInterface
#endif // SUBJECTINTERFACE_H_
You have a circular dependency; Observer.h includes SubjectInterface.h, and vice versa. You will need to break this with a forward declaration.
I am having troubles with inclusion model of templates implementation and cyclic dependency of *.h and *.hpp files.
Let us imagine the following inheritance sequences of classes:
A->B->C,
A->A1,
B->B1, C->C1
where A, A1 are abstract classes.
A.h (Abstract class)
#ifndef A_H
#define A_H
template <class A>
{
//some code
virtual A() = 0;
};
#include "A.hpp"
#endif
A.hpp
#ifndef A_HPP
#define A_HPP
#include "B.h" //Circular dependency
#include "C.h" //Circular dependency
void create Object(A ** a, unsigned int code)
{
switch (code)
{
case 0: *a = new B(); break;
case 1: *a = new C();
};
}
#endif
B.h
#ifndef B_H
#define B_H
#include "A.h"
template <class T>
class B : public A <T>
{
//Some code
};
C.h
#ifndef C_H
#define C_H
#include "C.h"
template <class T>
class C : public B <T>
{
//Some code
};
A1.h (abstract class)
#ifndef A1_H
#define A1_H
#include "A.h"
template <class T>
class A1 : public A <T>
{
//Some code
};
#include "A.hpp"
#endif
A1.hpp
#ifndef A1_HPP
#define A1_HPP
#include "B1.h" //Circular dependency
#include "C1.h" //Circular dependency
void create Object(A1 ** a1, unsigned int code)
{
switch (code)
{
case 0: *a = new B1(); break;
case 1: *a = new C1();
};
#endif
B1.h
#ifndef B1_H
#define B1_H
#include "B.h"
template <class T>
class B1 : public B <T>
{
//Some code
};
C1.h
#ifndef C1_H
#define C1_H
#include "C.h"
template <class T>
class C1 : public C <T>
{
//Some code
};
How to make a reasonable including to avoid the circular dependency? I try to replace include directives with forward declarations, but unfortunately it was not enough for compiler...
A.hpp
#ifndef A_HPP
#define A_HPP
template <class T>
class A;
template <class T>
class B;
//some code
#endif
1.hpp
#ifndef A1_HPP
#define A1_HPP
template <class T>
class A;
template <class T>
class B;
//some code
#endif
You'll need to:
Define each class in its header
Have each header include the dependencies it needs
Not **require** that the dependency succeed in defining the class, and forward-declare it as well.
If you do all of the above you'll allow other code to include the headers in any order but they'll still work in their "circulariness". No my spelling checker didn't know that word, as I just made it up.
In other words, you need to do things like this:
foo.h:
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class bar; // THIS IS THE CRITICAL LINE
class foo {
// ... uses bar
}
#endif /* FOO_H */
bar.h
#ifndef BAR_H
#define BAR_H
#include "foo.h"
class bar; // THIS IS THE CRITICAL LINE
class bar {
// ... uses foo
}
#endif /* BAR_H */
A.hpp and A1.h should not include anything related to B or C.
Why does A's implementation need to know about B & C at all? If the parent's implementation depends on details of a specific child, it seems like the inheritance isn't being used properly.
It seems likely you can just remove those includes and fix the problem that way.
Can you show us specifically why you need to include B & C within A's header/implementation?