ZaellixA
ZaellixA

Reputation: 214

Operator with different types

I am quite new to C++ and I am implementing a, quite simple, (linear algebra) vector class as a template.

Now, I am trying to implement the addition and subtraction operators but with the ability to perform the operations not only between vectors, but also with scalars (short, long, float, double, etc.) (this will be an element-wise operation).

The relevant part of the code can be seen below and both declaration and definition (implementation) of the template class is in the same .hpp file (checked this question and didn't seem to provide a solution for this exact reason).

// Forward declaration of friend function
template<class S, class T>
Vector<T> operator +(const S& scalar, const Vector<T>& vec);

template<class T>
class Vector {
  public:
    Vector(unsigned long length);
    Vector(Vector<T> vec);

    template<class S>
    friend Vector<T> operator +(const S& scalar, const Vector<T>& vec);
    
    template<class S>
    Vector<T> operator +(const S& scalar) const;

    template<class S>
    Vector<T>& operator +=(const S& scalar);

  private:
    unsigned long mLen;
    T* mData;
};

// Constructor
Vector<T>::Vector(const unsigned long length) : mLen(length) {
  mData = new T[mData];

  for(unsigned long i = 0; i < mLen; ++i) {
    mData[i] = T();
  }
}

// Copy constructor
template<class T>
Vector<T>::Vector(Vector<T> vec) {
  mLen = 0;
  mData = nullptr;
  std::swap(mData, vec.mData);
}

// Implementation of the operators
template<class S, class T>
Vector<T> operator +(const S& scalar, const Vector<T>& vec) {
  return vec + scalar;
}

template<class T> template<class S>
Vector<T> operator +(const S& scalar) const {
  Vector<T> result(*this);
  return result += scalar;
}

template<class T> template<class S>
Vector<T>& Vector<T>::operator +(const S& scalar) {
  // mLen is the length of the object (member variable)
  for(unsigned long i = 0; i < mLen; ++i) {
    mData[i] += scalar; // mData is the array holding the values (member variable)
  }

  return *this;
}

The addition between a Vector and a scalar is implemented (as a member function though) and works as intended (result-wise). Furthermore, I can guarantee (for the moment at least) that S will always be one of short, int, float or double.

So, when in my tests I try to do something like

Vector<int> vec(10);

1 + vec;

I get the following error

Undefined symbols for architecture x86_64: "operator+(int const&, Vector const&)", referenced from: _main in main.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation)

I am working on XCode 11.3.1 for this project.

Any insights would be most welcome. Additionally, I know that my understanding of templates (and a whole lot more about C++) is still very limited, so if you would require more information to get a better idea please let me know.

Thanks in advance.

Upvotes: 1

Views: 370

Answers (1)

Ted Lyngmo
Ted Lyngmo

Reputation: 117298

First, the free function template doesn't need to be a friend since it's not directly accessing the private members in Vector<T>. It also doesn't need to be forward declared. This can also be greatly simplified by using a std::vector<T> to keep the data to not have to implement the rule of 5 manually.

Example:

#include <vector>

template<class T>
class Vector {
public:
    Vector(unsigned long length) :
        mData(length) // create the vector
    {}

    template<class S>
    Vector& operator+=(S scalar) {
        for(auto& v : mData) v += scalar;  // add "scalar" to all elements in the vector
        return *this;
    }

    template<class S>
    Vector operator+(S s) const {
        Vector copy(*this);       // using the implicitly defined copy constructor
        copy += s;                // use the above operator+=
        return copy;
    }

private:
    std::vector<T> mData;
};

template<class S, class T>
Vector<T> operator +(S scalar, const Vector<T>& vec) {
    return vec + scalar;
}

Upvotes: 4

Related Questions