following situation:
I have in one dll a template class Point
namespace Image
{
template<typename T> class Point
{
.
.
.
and tring to use this class in another dll. The class looks like:
//Base.h
template<typename T> class Point;
class Base{
Point<double> _Point;
};
//Child.h
#include "Base.h"
class Child : public Base{
Child(Point<double> pt);
doSth();
}
//Child.cpp
#include "Child.h"
#include "Point.h"
Child::Child(Point<double> pt){
_Point = pt;
}
Child::dosth(){
Point<double> p = _Point; // In this Row i get an "undefined type 'Point<double>' Error
}
Any ideas why i get the error?
is my idea totally wrong to forward declare the Point-Class in the header file and make the include in the .cpp ?
Thank you very much, have a nice day!
With the forward declaration you have in Base.h it doesn't matter if you used using namespace Image; first, the template class you declare in Base.h is still in the global namespace and not in the Image namespace. And that declaration will take precedence over the one in the Image namespace.
So there are really two solutions here: Either explicitly use Image::Point, or remove the forward declaration in Base.h (and include the header file where Image::Point<> is defined).
Related
I made a smaller reproducible version of the code that gave me these errosr: 'MyNamespace::MySecondClass': 'class' type redefinition, 'print': is not a member of 'MyNamespace::MySecondClass'. Is there any way of working around this problem?
// MyClass.h
#pragma once
namespace MyNamespace {
class MySecondClass {};
}
// MyClass.cpp
#include "MyClass.h"
#include <iostream>
using namespace std;
class MyNamespace::MySecondClass
{
public:
void print(const char* msg)
{
cout << msg << endl;
}
};
The problem is that in MyClass.h you define a class MySecondClass as an empty class. When you the define your class in MyClass.cpp you give a different definition, which contains some new members. This infringes the One Definition Rule (ODR).
Solution 1
remove {} in the header. This will tell the compiler that you declare that such a class exists but that it will be defined later. Your code would compile. Unfortunately if you’d include the header in other cpp, these could make only a very very limited use of MySecondClass.
Solution 2
define in the header the class with all its members (but without providing the implementation of the member functions:the signature is sufficient). This would allow the class to be used in whichever cpp that
would include it:
// MyClass.h
#pragma once
namespace MyNamespace {
class MySecondClass {
public:
void print(const char* msg);
};
}
You’d then define the members of the class in its cpp in the appropriate namespace:
// MyClass.cpp
#include <iostream>
#include "MyClass.h"
using namespace std;
namespace MyNamespace {
// member functions
void MySecondClass::print(const char* msg)
{
cout << msg << endl;
}
}
Remark: the include sequence in the cpp should first include the standard library headers, then only your own headers. It makes no difference in your simple example, but better get used the good practices immediately.
#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).
I'm using the CRTP pattern to create an interface, which other classes will derive from.
In the interface I forward declare a structure (important because I don't want to drag other stuff in the interface), but I include its definition in the cpp file which defines the interface.
Interface.h
#ifndef INTERFACE_H_INCLUDED
#define INTERFACE_H_INCLUDED
// forward declaration
class ForwardDecl;
template <class Derived>
class Interface
{
public:
ForwardDecl interfaceMethod();
};
#endif // INTERFACE_H_INCLUDED
ForwardDecl.h
#ifndef FORWARDDECL_H_INCLUDED
#define FORWARDDECL_H_INCLUDED
struct ForwardDecl
{
ForwardDecl(int i):internal(i)
{}
int internal;
};
#endif // FORWARDDECL_H_INCLUDED
Interface.cpp
#include "Interface.h"
#include "ForwardDecl.h"
template<class Derived>
ForwardDecl Interface<Derived>::interfaceMethod()
{
return static_cast<Derived *>(this)->implementation_func();
}
And this is the implementation which implements the interface
Implementation.h
#ifndef IMPLEMENTATION_H_INCLUDED
#define IMPLEMENTATION_H_INCLUDED
#include "Interface.h"
class ForwardDecl;
class Implementation: public Interface<Implementation>
{
friend class Interface<Implementation>;
private:
ForwardDecl implementation_func();
};
#endif // IMPLEMENTATION_H_INCLUDED
Implementation.cpp
#include "Implementation.h"
#include "ForwardDecl.h"
#include <iostream>
struct ForwardDecl Implementation::implementation_func()
{
ForwardDecl fd(42);
std::cout << fd.internal << std::endl;
return fd;
}
And the main file
#include <iostream>
#include "Implementation.h"
#include "ForwardDecl.h"
using namespace std;
int main()
{
Implementation impl;
ForwardDecl fd = impl.interfaceMethod();
cout << fd.internal << endl;
return 0;
}
I get linking errors on both VS and GCC.
Any workaround? Thank you.
There is a flaw in your very approach: You have a public function returning a ForwardDecl instance, so every client wanting to use this function also must include the according definition of that type, which implies you can make that type public from the beginning. This includes making the function definition inline, which will fix your linker problems.
However, if you really want to hide the content of that structure and you are sure clients don't need it directly, you can declare it and then pass around references to such a structure (or pointers, but raw pointers are evil albeit not in the same league of evil as #macros). In that case, I would still make the function definition inline.
If you really, really want to not make the function inline, you can also explicitly instantiate the function template for the types that you need. You would add at the end of the template's .cpp file something like template class Interface<int>; (I don't remember the exact syntax so take that with a few flakes of fleur de sel, check out the C++ FAQ at parashift.com for more info). This makes the template a little less universal though, as it requires adjustments for any type that you want to use it with, but it can be an approach in some corner cases.
The definitions of function templates and member functions of class templates need to be visible in all translation units that instantiate those templates. That is, you shouldn't put template definitions in a .cpp file, which means you need to move the contents of Interface.cpp up into Interface.h.
Here is basically what my class layout is:
GameDriver.h:
#ifndef GAMEDRIVER_H
#define GAMEDRIVER_H
#include "CameraSystem.h"
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
#endif
CameraSystem.h:
#ifndef CAMERASYSTEM_H
#define CAMERASYSTEM_H
#include "Tickable.h"
class GameDriver;
class CameraSystem: public Tickable { //Complains here
//Stuff
};
#endif
Tickable.h:
#ifndef TICKABLE_H
#define TICKABLE_H
#include "GameDriver.h"
class GameDriver;
class Tickable {
//Stuff
};
#endif
Here is the error I get:
CameraSystem.h:9 error: expected class-name before '{' token
Forward declaring Tickable does not work either. Any help? Thanks in advance.
If you forward delcare a class you shouldn't include the class' header.
#include "CameraSystem.h" // DO NOT INCLUDE THIS
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
Ok, I see two problems here.
First: Your forward declarations are useless. You are writing (using GameDriver.h: as an example):
#include "CameraSystem.h"
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
Here CameraSystem will already be known by including CameraSystem.h, so the forward declaration is nonsense. What you meant to write was:
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
Second: Where you really would need a forward declaration you cannot use it, as you cannot derive from a forward declared class:
#include "Tickable.h"
class CameraSystem: public Tickable { //Complains here
//Stuff
};
Note that a forward declaration works only if you are not using the forward declared class directly as a class member. You are then restricted to pointers or references to the forward declared class. The reason for this is, that the compiler does not know the memory layout of the class unless its completely known (i.e. by including the header file). For example:
class CameraSystem;
class GameDriver {
CameraSystem m_cameraSystem;
};
will NOT work. However,
class CameraSystem;
class GameDriver {
CameraSystem *m_cameraSystem;
CameraSystem& m_otherCameraSystem;
};
will. Of course you will still have to include the correct header files in your *.cpp file.
You can't resolve such circular dependencies. However, you've got the solution (partially):
I.e. instead of including a header, just use a forward declaration. If you do this right, there shouldn't be any issues. However, try to group your program into logical elements/groups and only add cross-references if they're requied (e.g. the game has to know about and access the camera, but the camera shouldn't have to access the game system as a whole).
You can't inherit from a class that has not been declared.
Pre-processing Tickable.h gives you:
class GameDriver;
class CameraSystem: public Tickable { //Complains here
//Stuff
};
class CameraSystem; //Forward declaration
class GameDriver {
//Stuff
};
class GameDriver;
class Tickable {
//Stuff
};
See how Tickable hasn't even been forward declared when you inherit from it?
Try adding #pragma once at the very beginning of each header file.
You should somehow tell the compiler to only put those once. That's one way. Another is using #ifndef X and #define X.
If this doesn't solve it, try to just eliminate the circular dependency - it doesn't seem like it has to happen...
I don't understand what is wrong with this code.
gcc reports "Client.h:29: error: expected template-name before '<' token"
As far as I'm aware I'm followed the template syntax correctly, but it could be that the error message is confusing me and is not the problem
client.h
class Client : public BaseDll<DllClient> [line 29]
{
..snip..
};
basedll.h
template<typename T>
class BaseDll : public Base
{
public:
..snip..
private:
T* _dll;
};
class Base{
};
template<typename T>
class BaseDll:public Base{
public:
private:
T* _dll;
};
class DllClient{
};
class Clien:public BaseDll<DllClient>
{
};
this compiled for me without problems, so I don't think the problem lies within what you posted. My best bet would be that you made a syntax error in client.h, maybe something as simple as forgetting a semicolon after another class definition or some macro that's messing with your code
I'm so sorry everyone, a school-boy error has been made, BaseDll is declared in another namespace. As soon as I added the namespace qualifier, the problem has gone.
Maybe it's just an easy problem: Have you included basedll.h in client.h?
to cover the basics:
does client-h #include basedll.h? do they user different include guards?
Further troubleshooting:
does it work with a non-template base class?
does it work then you typedef the template instaltiation:
typedef BaseDll<DllClient> tClientBase;
class Client : public tClientBase { ... }
[edit] OK, next:
if you put the following two lines directly under the BaseDll declaration:
template <typename T>
class BaseDll
{ ...
};
class DummyFoo;
typedef BaseDll<DummyFoo> tDummyFoo;
I think you snipped away the problem. Are you including something to define 'DllClient' ?
A possible cause of this is that there is an inter-dependency between the different header files:
// client.h
#ifndef CLIENT
#define CLIENT
#include "base.h"
// ...
class Client : public BaseDll<DllClient>
{
// ..snip..
};
#endif
// base.h
#ifndef BASE
#define BASE
#include "client.h"
template<typename T>
class BaseDll : public Base
{
public:
// ..snip..
private:
T* _dll;
};
#endif
Now imagine we're parsing 'base.cpp' then the preprocessor will do the following:
#include "base.h"
#ifndef BASE <--- BASE unset, keep going
#define BASE
#include "client.h"
#ifndef CLIENT
#define CLIENT
#include "base.h"
#ifndef BASE <--- BASE set, skip base.h, return to client.h
class client
: public BaseDll<DllClient> <-- ERROR, BaseDll not defined.
If this is the problem, then you potentially can get around it by forward declaring the base template in client.h:
// client.h
#ifndef CLIENT
#define CLIENT
// #include "base.h" <-- remove include
template <typename DLL_CLIENT>
class BaseDll;
// ...
class Client : public BaseDll<DllClient>
{
// ..snip..
};
#endif