Circular dependency- Incompatible type question

I read Disch article here in c++ forum about headers
http://www.cplusplus.com/forum/articles/10627/

I have a code here that is somehow confusing

ResourceHolder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using namespace std;
template<typename Resource, typename Identifier>
class ResourceHolder{
public:
	void load(Identifier id, const std::string &filename);

	template<typename Parameter>
	void load(Identifier id, const std::string &filename, const Parameter &secondParam);

	Resource &get(Identifier id);
	const Resource &get(Identifier id) const;
private:
	void	insertResource(Identifier id, std::unique_ptr<Resource> resource);


private:
	std::map<Identifier, std::unique_ptr<Resource>> mResourceMap;
	
};



ResourceIdentifier.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Forward declaration of SFML classes
namespace sf
{
	class Texture;
}

namespace Textures
{
	enum  ID
	{
		Eagle,
		Raptor,
		Desert,
	};
}

// Forward declaration and a few type definitions
template <typename Resource, typename Identifier>
class ResourceHolder;

typedef ResourceHolder<sf::Texture, Textures::ID> TextureHolder;



Aircraft.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once
#include "Entity.h"
#include "ResourceIdentifiers.h"

class Aircraft : public Entity
{
public:
	enum  Type{
		Eagle,
		Raptor
	};


	Aircraft(Type type, const TextureHolder& textures);

private:
	virtual void drawCurrent(sf::RenderTarget &target, sf::RenderStates states) const;
	
private:
	Type mType;
	sf::Sprite mSprite;
};


I believe this is using the right way and the wrong way base on the article i read.
Aircraft.h
include
ResourceIdentifier.h
which contains a forward declaration of
ResourceHolder.h


Stated in the article that you need to use pointer to class or reference to class if you are going to forward declare.

In my code they use forward declaration but never use pointer to class. Its actually a template class


Thing is that when I got an error on my Aircraft.cpp about incompatible type

Aircraft.cpp
1
2
3
4
5
6
#include "Aircraft.h"
#include "ResourceHolder.h" // --------- I got an error if this is not included.

Aircraft::Aircraft(Type type, const TextureHolder &textures) : mType(type), mSprite(textures.get(toTextureID(type))) //---------->  this is where i get an error if ResourceHolder.h is not included
{
}



But this is confusing. I included the
ResourceIdentifier.h
that has a class forward declaration of
ResourceHolder.h
, in my
Aircraft.h
.

Why do i get that error? Everything is linked together. ResourceHolder also has its own class declaration in diferent file which i did not included here. But every class has a declaration.


Also texture is a reference to TextureHolder that is on ResourceIdentifier.h. Why do i have to declare the ResourceHolder.h again?


Last edited on
What is the error message?
Incompatible type.

So was wondering how and why? since everything is linked together
Was that all? I would expect much more words from a compiler.
When the compiler encounters line 14 of aircraft.h, it has to expand the typedef for TextureHolder. It can't do that because the only thing it knows about ResourceHolder is that it is an incomplete template. Hence the need for the include of "resourceholder.h".

Since resourceidentifier.h uses ResourceHolder, the include for resourceholder.h should really be at the front of resourceidentifier.h.

Also, you have no include guards in your headers. Include guards are important to prevent declaring the same things more than once and allow you to include headers in the order you need them without worrying about duplicate inclusion.
@keskiverto

Here is the whole error
IntelliSense: incomplete type is not allowed. Thats all it shows

@AbstractionA non

Thats really confusing now. On the article it works fine just by forward class. Since its just a reference to object its should be okay. One object I use from ResourceHolder is the get() but its via reference of &texture.

Can you give me a simple example about this? its confusing in my part.
Reread section 8 in Disch's article. Note in particular the following statement:
While this seems perfectly logical, it doesn't work! (Although, logically you really think it should. This is an irritation of the language). Because 'A' isn't really a class, but rather a typedef, the compiler will bark at you.

There is a difference between a forward class (which will work) and a incomplete template (which will not).
A practical solution to this problem is to create an alternative header which has the forward declarations of your templated classes and their typedefs. Here's a more elegant way to approach the above example:




//a.h

#include "b.h"

1
2
3
4
5
6
template <typename T>
class Tem
{
 /*...*/
  B b;
};




//a_fwd.h

1
2
template <typename T> class Tem;
typedef Tem<int> A;


//b.h

1
2
3
4
5
6
7
#include "a_fwd.h"

class B
{
 /*...*/
  A* ptr;
};




This allows B to include a header which forward declares A without including the entire class definition.


This means that class B would be the Aircraft and class A would be the ResourcecHolder and class a_fwd.h would be my ResourceIdentifier

Its the same concept. I class fowarded the A(ResourceHolder) to a_fwd.h(ResourceIdentifer) then included it on my B(Aircraft). Then I use a reference to a typedef ResourceHolder a_fwd(ResourceIdentifier).
Last edited on
Topic archived. No new replies allowed.