I have the following problem in my project that contains several modules (I am sorry but I could not find a simpler example) :
- Module1 defines a full template class ILocatable
- Module2 defines a class Component
- Module3 defines a class LocatableEntity that inherits from ILocatable < MyVector3D> (here, MyVector3D is an std::array<double,3>)
- Module4a uses modules 1,2,3, and defines a class LocatableComponent4a which inherits from Component and ILocatable < MyVector3D > that uses LocatableEntity
- Module4b uses modules 1,2,3,4a, a defines a class LocatableComponent4b which inherits from Component and ILocatable < MyVector3D > and uses LocatableComponent4a and LocatableEntity
Module1 and Module3 are static libraries. Module2, Module4a, Module4b are shared libraries. All modules compile fine except Module4b where I get the following error (with Visual C++, not with Linux/GCC) :
Project5_Module4a.lib(Project5_Module4a.dll) : error LNK2005: "public: virtual __cdecl Project5::Module1::ILocatable<class std::array<double,3> >::~ILocatable<class std::array<double,3> >(void)" (??1?$ILocatable@V?$array@N$02@std@@@Module1@Project5@@UEAA@XZ) déjà défini(e) dans Project5_Module3.lib(LocatableEntity.obj)
Please not that in Debug mode, there are more duplicate symbols (one for each method of ILocatable)
How can I cope with this ? When Module3 is linked dynamically the problem disappears, but I really would like to keep the static libraries. I also tried to instanciate the template with std::array<double,3> in Module3 but :
- This didn't solve my problem
- Most of the users of my project shall use other instanciations, such as Eigen::Vector3d or osg::Vec3d or whatever.
Many thanks for any help !!!
The full project is available here : https://ufile.io/1tkrt6d6 (needs CMake). Here are some parts of code :
namespace Module1 {
template <class Vector3D>
class ILocatable {
protected:
inline ILocatable() {
this->position[0] = 0.0; this->position[1] = 0.0; this->position[2] = 0.0;
this->frame = Frame::WGS84;
}
public:
virtual inline ~ILocatable() {}
inline const Vector3D& getPosition() const { return this->position; }
inline void setPosition(const Vector3D& value) { this->position = value; }
inline Frame getFrame() const { return this->frame; }
inline void setFrame(Frame value) { this->frame = value; }
private:
Vector3D position;
Frame frame;
};
} // namespace Module1
namespace Module3 {
typedef std::array<double, 3> MyVector3D;
class Project5_Module3_EXPORT LocatableEntity : public Module1::ILocatable<MyVector3D> {
public:
LocatableEntity();
virtual ~LocatableEntity();
};
} // namespace
namespace Module4a {
typedef std::array<double, 3> MyVector3D;
class Project5_Module4a_EXPORT LocatableComponent4a : public Module2::Component, public Module1::ILocatable<MyVector3D> {
public:
LocatableComponent4a();
virtual ~LocatableComponent4a();
void move() {
Module3::LocatableEntity locatableEntity;
locatableEntity.setPosition(this->getPosition());
locatableEntity.setFrame(this->getFrame());
Module3::move(locatableEntity);
this->setPosition(locatableEntity.getPosition());
this->setFrame(locatableEntity.getFrame());
}
};
} // namespace Module4a
namespace Module4b {
typedef std::array<double, 3> MyVector3D;
class Project5_Module4b_EXPORT LocatableComponent4b : public Module2::Component, public Module1::ILocatable<MyVector3D> {
public:
LocatableComponent4b();
virtual ~LocatableComponent4b();
void move();
void join(const Module4a::LocatableComponent4a& otherComponent) {
this->setPosition(otherComponent.getPosition());
this->setFrame(otherComponent.getFrame());
}
};
} // namespace Module4b