0

I am not very familiar with templates in C++ so I am struggling to solve the following problem.

I have the classes Vector2D and Vector3D but I want them to inherit from a class Vector. To be able to define common functions in Vector I am using CRTP (Curiously Recurring Template Pattern).

This is a shortend version of my Vector class:

#pragma once

#include "../stdafx.h"

template <class VectorImpl>
class Vector {
public:
    VectorImpl& operator=(const VectorImpl& other);

    virtual const float operator*(const VectorImpl& other) const = 0;

    friend const VectorImpl operator*(const float& scalar, const VectorImpl& other);
    virtual VectorImpl& operator*=(const float& scalar) = 0;

    float abs() const;

    virtual std::string toString() const = 0;

    virtual ~Vector() = 0 {};
 
protected:
    virtual void copyFrom(const VectorImpl& other) = 0;
};

-----------------------------------------------------------------------------------------

#include "Vector.h"
#include "Vector2D.h" // edit
#include "Vector3D.h" // edit

template <class VectorImpl>
VectorImpl& Vector<VectorImpl>::operator=(const VectorImpl& other) {
    this->copyFrom(other);

    // edit
    // return *this;
    return static_cast<VectorImpl&>(*this);
}

template <class VectorImpl>
const VectorImpl operator*(const float& scalar, const VectorImpl& other) {
    VectorImpl result = other;
    result *= scalar;
    return result;
}

template <class VectorImpl>
float Vector<VectorImpl>::abs() const {
    const VectorImpl thisImpl = static_cast<const VectorImpl&>(*this); // edit
    return std::sqrt(thisImpl * thisImpl);
}

// edit
template class Vector<Vector2D>;
template class Vector<Vector3D>;

And this is a shortend version of my Vector2D class:

#pragma once

#include "../stdafx.h"
#include "Vector.h"

class Vector2D :
    public Vector<Vector2D> {
public:
    Vector2D();
    Vector2D(const Vector2D& other);
    Vector2D(const float& xPos, const float& yPos);

    const float operator*(const Vector2D& other) const;

    Vector2D& operator*=(const float& scalar);

    std::string toString() const;

    ~Vector2D();

protected:
    void copyFrom(const Vector2D& other);

private:
    float xPos;
    float yPos;
};

-----------------------------------------------------------------------------------------

#include "Vector2D.h"

Vector2D::Vector2D() :
xPos(0.0f),
yPos(0.0f) {
}

Vector2D::Vector2D(const Vector2D& other) {
    this->copyFrom(other);
}

void Vector2D::copyFrom(const Vector2D& other) {
    if (this != &other) {
        this->xPos = other.getXPos();
        this->yPos = other.getYPos();
    }
}

Vector2D::Vector2D(const float& xPos, const float& yPos) {
    this->xPos = xPos;
    this->yPos = yPos;
}

const float Vector2D::operator*(const Vector2D& other) const {
    return this->xPos * other.getXPos() + this->yPos * other.getYPos();
}

Vector2D& Vector2D::operator*=(const float& scalar) {
    this->xPos *= scalar;
    this->yPos *= scalar;
    return *this;
}

std::string Vector2D::toString() const {
    std::string ret = std::to_string(this->xPos);
    ret += " ";
    ret += std::to_string(this->yPos);

    return ret;
}

Vector2D::~Vector2D() {
    // intentionally left blank
}

The problem is, for every call of a method from Vector2D (Vector3D respectively) that is implemented in Vector I get an LNK2019 error (unresolved external symbol 'symbol' referenced in function 'function'). I am quite sure that I am doing somethin wrong with my template implementation but I can't figure out what it is. I am researching for hours now.

I appreciate any help, so thanks in advance.

EDIT:

I added the necessary instantiations of my template classes but now I get casting errors. Adding

VectorImpl result = static_cast<const VectorImpl>(*this);

or

VectorImpl result = static_cast<VectorImpl>(*this);

doesn't change the problem. What I am I still missing here?

EDIT 2:

Okay of course it hast to be static_cast<const VectorImpl&>(*this). I also added these casts but now I get that damn linking error again. This time only the functions friend operator* and abs can't be linked. I don't see much difference to the other functions. So why are they problematic?

Community
  • 1
  • 1
Lilo
  • 341
  • 2
  • 14
  • If you don't explicitly instantiate template `Vector` (I don't see you do), then I guess [Why can templates only be implemented in the header file?](http://stackoverflow.com/q/495021/3953764) – Piotr Skotnicki Mar 25 '16 at 15:28
  • @PiotrSkotnicki Thanks for that hint I added my changes above. But now I get casting errors and adding `static_cast(*this)` for examlpe doesn't change anything. :( Any ideas? – Lilo Mar 25 '16 at 15:44
  • I believe you want `static_cast(*this)` (see the ampersand), or `static_cast(*this)` (`const&`). And also, I don't think it's a good idea to implement operators as virtual functions – Piotr Skotnicki Mar 25 '16 at 15:45
  • I'd suggest you remove this question, fix the problem with the linker error, and ask a new specific question – Piotr Skotnicki Mar 25 '16 at 15:49
  • Okay the missing & did the trick but it doesn't help with the rest. Why isn't this `VectorImpl result = static_cast(*this);` or `VectorImpl result = static_cast(*this);` working? Could you please elaborate why implementing operators as virtual function is not a good idea? – Lilo Mar 25 '16 at 15:53
  • `static_cast(*this);` is an attempt to create `VectorImpl` from `*this`; you don't have such a constructor – Piotr Skotnicki Mar 25 '16 at 15:59
  • `friend const VectorImpl operator*` is not a function template. in the definition it is, so it's actually a distinct function – Piotr Skotnicki Mar 25 '16 at 16:18
  • @PiotrSkotnicki I read [C++ Template Classes and Friend Function Details](http://web.mst.edu/~nmjxv3/articles/templates.html) but I am not quite sure how exactly I should implement approach #2. Could you help me once more, please? – Lilo Mar 25 '16 at 16:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/107353/discussion-between-lilo-and-piotr-skotnicki). – Lilo Mar 25 '16 at 16:42
  • that depends, perpahs use something like [this](http://coliru.stacked-crooked.com/a/4eeb02e9f0af7bb0) – Piotr Skotnicki Mar 25 '16 at 16:43
  • But that would mean, that all classes inheriting from `Vector` would need to implement that function, wouldn't it? That ist not what I want, since it does the same thing for any vector. And why is the friend function in your attempt not pure virtual? – Lilo Mar 25 '16 at 16:51

0 Answers0