0

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.

Yvus
  • 338
  • 1
  • 20
  • See the top of your question, or "Linked" to the right of the question. – Some programmer dude May 06 '16 at 08:27
  • @JoachimPileborg: thanks, you pointed me in the right direction. I didn't realize this thing with the template needing to stay in the headers. The link in the answer you pointed out [isocpp](https://isocpp.org/wiki/faq/templates#separate-template-class-defn-from-decl) made it work. – Yvus May 06 '16 at 08:57

0 Answers0