I am modifying an open source library to better fit my needs. This library has most of its code all written in the header files. for one of the header GteQuaternion.h
I want to reuse code that is in the header GteRotation.h
which actually includes GteQuaternion.h
. Hence, to avoid circular includes. I locate in a source file GteRotation.cpp
the code I am impementing using the GteRotation.h
.
GteQuaternion.h
#pragma once
#include <Mathematics/GteVector4.h>
namespace gte {
template <typename Real> class Quaternion : public Vector<4,Real> { public:
Quaternion();
Quaternion(Quaternion const& q);
Quaternion(Vector<4,Real> const& q); Quaternion(Vector<3, Real> const& v, Real theta); Quaternion(Real x, Real y, Real z, Real w); Quaternion(int axes1, int axes2, int axes3, Real angle1, Real angle2, Real angle3);
// Assignment.
Quaternion& operator=(Quaternion const& q);
Quaternion& operator=(Vector<4,Real> const& q);
// Special quaternions.
static Quaternion Zero(); // z = 0*i + 0*j + 0*k + 0
static Quaternion I(); // i = 1*i + 0*j + 0*k + 0
static Quaternion J(); // j = 0*i + 1*j + 0*k + 0
static Quaternion K(); // k = 0*i + 0*j + 1*k + 0
static Quaternion Identity(); // 1 = 0*i + 0*j + 0*k + 1
Vector<3, Real> getAxis() const;// get axis of rotation
Real getAngle() const; // get angle of rotation
};
template <typename Real> Quaternion<Real> operator*(Quaternion<Real> const& q0, Quaternion<Real> const& q1);
<typename Real> Quaternion<Real> Inverse(Quaternion<Real> const& q);
<typename Real> Quaternion<Real> Conjugate(Quaternion<Real> const& q);
. . .
<typename Real> Vector<3, Real> Rotate(Quaternion<Real> const& q, Vector<3, Real> const& v);
<typename Real> Quaternion<Real> quaternionChangeCoordinate(Quaternion<Real> const& q, Quaternion<Real> const& qRot);
template <typename Real> Quaternion<Real> Slerp(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1);
template <typename Real> Quaternion<Real> SlerpR(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1);
template <typename Real> Quaternion<Real> SlerpRP(Real t, Quaternion<Real> const& q0, Quaternion<Real> const& q1, Real cosA);
template <typename Real> Quaternion<Real>::Quaternion() { // Uninitialized. }
template <typename Real> Quaternion<Real>::Quaternion(Quaternion const& q) { this->mTuple[0] = q[0]; this->mTuple[1] = q[1]; this->mTuple[2] = q[2]; this->mTuple[3] = q[3]; }
template <typename Real> Quaternion<Real>::Quaternion(Vector<4, Real> const& q) { this->mTuple[0] = q[0]; this->mTuple[1] = q[1]; this->mTuple[2] = q[2]; this->mTuple[3] = q[3]; }
template <typename Real> Quaternion<Real>::Quaternion(Vector<3, Real> const& v, Real theta) { this->mTuple[0] = sin(theta / 2.)*v[0]; this->mTuple[1] = sin(theta / 2.)*v[1]; this->mTuple[2] = sin(theta / 2.)*v[2]; this->mTuple[3] = cos(theta / 2.); }
template <typename Real> Quaternion<Real>::Quaternion(Real x, Real y, Real z, Real w) { this->mTuple[0] = x; this->mTuple[1] = y; this->mTuple[2] = z; this->mTuple[3] = w; }
template <typename Real> Quaternion<Real>& Quaternion<Real>::operator=(Quaternion const& q) { Vector<4, Real>::operator=(q); return *this; }
. . .
GteQuaternion.cpp
#include <Mathematics/GteQuaternion.h>
namespace gte
{
template <typename Real>
Quaternion<Real>::Quaternion(int axes1, int axes2, int axes3, Real angle1, Real angle2, Real angle3)
{
EulerAngles<Real> euler(axis1,axis2,axis3,angle1,angle2,angle3);
Rotation<3, Real> rot(euler);
Quaternion<Real> q = (Quaternion<Real>)rot;
this->mTuple[0] = q[0];
this->mTuple[1] = q[1];
this->mTuple[2] = q[2];
this->mTuple[3] = q[3];
}
template <typename Real>
Vector<3, Real> Quaternion<Real>::getAxis() const
{
AxisAngle<3, Real> axis;
Rotation<3, Real> rot(*this);
axis = (AxisAngle<3, Real>)rot;
return Vector<3, Real>(axis.axis);
}
template <typename Real>
Real Quaternion<Real>::getAngle() const
{
AxisAngle<3, Real> axis;
Rotation<3, Real> rot(*this);
axis = (AxisAngle<3, Real>)rot;
return axis.angle;
}
}
I have the feeling that something is completely off here, since the Rotation
class should be raising a compiling error in the .cpp file. because no include of the GteRotation.h
file is done. But the output of the compilation looks the following:
1>------ Rebuild All started: Project: HydrosMathLibraryConsole, Configuration: Debug Win32 ------
1> HydrosMathLibraryConsole.cpp
1> HydSpatialVector.cpp
1> HydFrame.cpp
1> HydFrameList.cpp
1> HydFramedVector.cpp
1> GteQuaternion.cpp
1> Generating Code...
1>HydFrame.obj : error LNK2019: unresolved external symbol "public: class gte::Vector<3,double> __thiscall gte::Quaternion<double>::getAxis(void)const " (?getAxis@?$Quaternion@N@gte@@QBE?AV?$Vector@$02N@2@XZ) referenced in function "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl gte::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class gte::Frame const &)" (??6gte@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV12@ABVFrame@0@@Z)
1>HydrosMathLibraryConsole.obj : error LNK2001: unresolved external symbol "public: class gte::Vector<3,double> __thiscall gte::Quaternion<double>::getAxis(void)const " (?getAxis@?$Quaternion@N@gte@@QBE?AV?$Vector@$02N@2@XZ)
1>HydFrame.obj : error LNK2019: unresolved external symbol "public: double __thiscall gte::Quaternion<double>::getAngle(void)const " (?getAngle@?$Quaternion@N@gte@@QBENXZ) referenced in function "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl gte::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class gte::Frame const &)" (??6gte@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV12@ABVFrame@0@@Z)
1>HydrosMathLibraryConsole.obj : error LNK2001: unresolved external symbol "public: double __thiscall gte::Quaternion<double>::getAngle(void)const " (?getAngle@?$Quaternion@N@gte@@QBENXZ)
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "public: __thiscall gte::FVector<double>::FVector<double>(void)" (??0?$FVector@N@gte@@QAE@XZ) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "public: __thiscall gte::FVector<double>::FVector<double>(class std::array<double,3> const &,class gte::Frame *)" (??0?$FVector@N@gte@@QAE@ABV?$array@N$02@std@@PAVFrame@1@@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "public: __thiscall gte::FVector<double>::FVector<double>(class std::initializer_list<double>,class gte::Frame *)" (??0?$FVector@N@gte@@QAE@V?$initializer_list@N@std@@PAVFrame@1@@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "public: __thiscall gte::FVector<double>::FVector<double>(int,class gte::Frame *)" (??0?$FVector@N@gte@@QAE@HPAVFrame@1@@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "public: class gte::FVector<double> __thiscall gte::FVector<double>::getInParentFrame(class gte::Frame * const)const " (?getInParentFrame@?$FVector@N@gte@@QBE?AV12@QAVFrame@2@@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "public: class gte::FVector<double> __thiscall gte::FVector<double>::getInChildFrame(class gte::Frame * const)const " (?getInChildFrame@?$FVector@N@gte@@QBE?AV12@QAVFrame@2@@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "public: class gte::FVector<double> __thiscall gte::FVector<double>::getInFrame(class gte::Frame * const)const " (?getInFrame@?$FVector@N@gte@@QBE?AV12@QAVFrame@2@@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "public: bool __thiscall gte::FVector<double>::operator==(class gte::FVector<double> const &)const " (??8?$FVector@N@gte@@QBE_NABV01@@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl gte::operator<<<double>(class std::basic_ostream<char,struct std::char_traits<char> > &,class gte::FVector<double> const &)" (??$?6N@gte@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV12@ABV?$FVector@N@0@@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "class gte::FVector<double> __cdecl gte::operator+<double>(class gte::FVector<double> const &,class gte::FVector<double> const &)" (??$?HN@gte@@YA?AV?$FVector@N@0@ABV10@0@Z) referenced in function _main
1>HydrosMathLibraryConsole.obj : error LNK2019: unresolved external symbol "class gte::FVector<double> & __cdecl gte::operator-=<double>(class gte::FVector<double> &,class gte::FVector<double> const &)" (??$?ZN@gte@@YAAAV?$FVector@N@0@AAV10@ABV10@@Z) referenced in function _main
1>C:\Users\Yves\Documents\GitLocalFolder\HydrosMathLibrary\HydrosMathLibraryConsole\Debug\HydrosMathLibraryConsole.exe : fatal error LNK1120: 13 unresolved externals
========== Rebuild All: 0 succeeded, 1 failed, 0 skipped ==========
Only linking errors!
I guess I am doing something wrong with visual studio express and the project configuration?
EDIT
My problem was the lack of understanding of the templates
. I have been pointed to the link isocpp found in the duplicate answer marking. See the comment below.
Therefore adding
template class Quaternion<double>;
template class Quaternion<float>;
at the end of the source file GteQuaternion.cpp
made it work.