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.
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;
}
Related
I am implementing the addition operator for a custom class. The function/operator invoked is neither a friend or a member function and adds a scalar value to the vector (the class is supposed to be a linear algebra vector class). Internally, this function calls the addition operator of the class which in turn calls the compound addition of the same class.
Below is the relevant part of the declaration of the class (this is a template class) along with the implementation of the constructors, the non-member function/operator and the compound addition operator (the addition operators follow further below to show the "issue").
template<class T>
class Vector {
public:
Vector(const unsigned long length); // Default ctor
Vector(const Vector<T>& vec); // Copy ctor
template<class S>
Vector<T> operator +(const S& scalar);
template<class S>
Vector<T>& operator +=(const S& scalar);
private:
unsigned long mLen;
T* mData;
};
template<class T, class S>
Vector<T> operator +(const S& scalar, const Vector<T>& vec);
// Implementation of ctors
template<class T>
Vector<T>::Vector(const unsigned long length) {
mLen = length;
mData = new T[length];
}
template<class T>
Vector<T>::Vector(const Vector<T>& vec) {
mLen = vec.mLen;
std::copy_n(vec.mData, vec.mLen, mData);
}
template<class T, class S>
Vector<T> operator +(const S& scalar, const Vector<T>& vec) {
return vec + scalar;
}
template<class T> template<class S>
Vector<T>& Vector<T>::operator +=(const S& scalar) {
for(unsigned long i = 0; i < mLen; ++i) {
mData[i] += scalar;
}
return *this;
}
As already stated, the implementation is based on the compound assignment operator. All operators seem to be working as intended, result-wise, but when I return the result of the compound assignment operation directly the copy constructor is invoked and I can't understand why. See the following examples for clarification.
Example where the copy constructor is invoked
template<class T> template<class S>
Vector<T> Vector<T>::operator +(const S& scalar) {
Vector<T> result(*this); // Normal copy ctor call
return result += scalar; // Here the copy ctor is invoked again!!!
}
Example where the copy constructor is not invoked
// Implementation of the addition operators
template<class T> template<class S>
Vector<T> Vector<T>::operator +(const S& scalar) {
Vector<T> result(*this); // Normal copy ctor call
result += scalar;
return result; // Here the copy ctor is NOT invoked
}
A main.cpp example could be the following
int main(int argc, const char* argv[]) {
Vector<T> vec(10);
1 + vec;
}
Now, when the first implementation of the addition operator is used, the copy constructor is called at the return statement (in addition to the line above which obviously makes perfect sense). When the operator is implemented in the second way, the copy constructor is only called once, when explicitly called in the above line.
I am using XCode 11.3.1 (on Mac obviously). Please let me know if you would like more information on the issue. If someone could shed some light here I would be grateful.
Since operator+= returns a reference, the return statement needs to copy this referenced value into the return value for the function. There is not a value available that the compiler can use to elide this call to the copy constructor.
Your first example is the equivalent of
template<class T> template<class S>
Vector<T> Vector<T>::operator +(const S& scalar) {
Vector<T> result(*this);
Vector<T> &ans = (result += scalar); // (Parens included for clarity)
return ans;
}
which should make it more obvious why the compiler must call the copy constructor in the return statement.
The second example returns the local result directly, so the copy constructor call is elided.
How can I make it so that (with objects of different template types) A*B and B*A give the same result, where the type of the result is determined according to the usual C++ type promotion rules?
For example:
int main()
{
number<float> A(2.0f);
number<double> B(3.0);
A*B; // I want 6.0 (double)
B*A; // I want 6.0 (double)
return 0;
}
At the moment, I can only multiply objects of the same template type. For example, something like this:
template<typename T>
class number
{
public:
number(T v) : _value(v) {}
T get_value() const { return _value; }
number& operator*=(const number& rhs)
{
_value *= rhs.get_value();
return *this;
}
private:
T _value;
};
template<typename T>
inline number<T> operator*(number<T> lhs, const number<T>& rhs)
{
lhs *= rhs;
return lhs;
}
EDIT: Or, as in the answers, I can multiply objects of different template types, but always returning the same type as lhs. Is there any way to instead return an object whose type is determined by the standard type promotion rules?
EDIT 2: I would like to avoid C++11 features if possible.
You have to templatize e.g. the rhsparameters:
template<typename T>
class number
{
public:
number(T v) : _value(v) {}
T get_value() const { return _value; }
template<class E>
number& operator*=(const number<E>& rhs)
{
_value *= rhs.get_value();
return *this;
}
private:
T _value;
};
template<class T, class E, class RET = decltype(T()*E())>
number<RET> operator*(number<T>& lhs, const number<E>& rhs)
{
return lhs.get_value()*rhs.get_value();
}
You can use std::common_type<> to obtain the type required for the return. For example
template<typename X>
struct number
{
// ...
template<typename Y>
number(number<Y> const&other); // needed in line 1 below
template<typename Y>
number&operator=(number<Y> const&other); // you may also want this
template<typename Y>
number&operator*=(number<Y> const&other); // needed in line 2 below
template<typename Y>
number<typename std::common_type<X,Y>::type> operator*(number<Y> const&y) const
{
number<typename std::common_type<X,Y>::type> result=x; // 1
return result*=y; // 2
}
};
I left out the implementations of the templated constructor and operator*=.
Unfortunately, std::common_type is C++11, which you want to avoid for obscure reasons. If you only work with built-in types (double, float, int, etc), you can easily implement your own version of common_type. However, if you want to do sophisticated meta-template programming, it is strongly recommended to move on to C++11 – it's already 4 years old and mostly backwards compatible.
You need a templated overload for the operator*()
template<typename T>
class number {
public:
// ...
template<typename U>
number& operator*=(const number<U>& rhs) {
// ...
}
// ...
};
And the same for the binary operator
template<typename T,typename U>
inline number<T> operator*(number<T> lhs, const number<U>& rhs) {
lhs *= rhs;
return lhs;
}
As an exercise to learn a little more about dynamic memory allocation in C++, I'm working on my own vector class. I'm running into a little difficulty overloading the sum operator, so I thought I'd turn here to get some insight into why this doesn't work. Here's what I have so far:
template<typename T>
class vector
{
private:
T* pointer_;
unsigned long size_;
public:
// Constructors and destructors.
vector();
template<typename A> vector(const A&);
template<typename A> vector(const A&, const T&);
vector(const vector<T>&);
~vector();
// Methods.
unsigned long size();
T* begin();
T* end();
vector<T>& push_back(const T&);
// Operators.
T operator[](unsigned long);
vector<T>& operator=(const vector<T>&);
friend vector<T>& operator+(const vector<T>&, const vector<T>&);
};
The template<typename A> vector(const A&) constructor looks like this:
template<typename T> template<typename A>
vector<T>::vector(const A& size)
{
this->pointer_ = new T[size];
this->size_ = size;
}
Finally, the operator+ operator looks like this:
template<typename T>
vector<T>& operator+(const vector<T>& lhs, const vector<T>& rhs)
{
vector<T> result(lhs.size_);
for (unsigned long i = 0; i != result.size_; i++)
{
result.pointer_[i] = lhs.pointer_[i] + rhs.pointer_[i];
}
return result;
}
My compiler (VS2013) returns an unresolved external symbol error when I try to compile this code, which (as I understand it) means there's a function declared somewhere that I haven't actually defined. I'm not sure where the problem is, however: the template<typename A> vector(const A&) constructor works fine. What am I missing?
You're not properly friending the template operator function. There are multiple ways to do this, each of which has advantages. One is the friend-the-world ideology where all expansions of the template are friends with each other. I prefer to be a bit more restrictive than that.
Above your vector class, do this:
template<typename T>
class vector;
template<typename T>
vector<T> operator+(const vector<T>& lhs, const vector<T>& rhs);
The proceed as before, but note the syntax in the friend declaration:
// vector class goes here....
template<typename T> class vector
{
.... stuff ....
friend vector<T> operator+<>(const vector<T>&, const vector<T>&);
};
Then define the rest as you have it. That should get you what I think you're trying to achieve.
Best of luck.
PS: invalid reference return value fixed in the above code.
Related to this question that I asked yesterday.
I'm building my own vector class to learn a little more about C++, and I'm having some difficulty implementing an overloaded operator+ that I can use to add vectors. Here's what my class looks like so far:
template<typename T>
class vector;
template<typename T>
vector<T> operator+(const vector<T>&, const vector<T>&);
template<typename T>
class vector
{
private:
T* pointer_;
unsigned long size_;
public:
// Constructors and destructors.
vector();
template<typename A> vector(const A&);
template<typename A> vector(const A&, const T&);
vector(const vector<T>&);
~vector();
// Methods.
unsigned long size();
T* begin();
T* end();
vector<T>& push_back(const T&);
// Operators.
T operator[](unsigned long);
vector<T>& operator=(const vector<T>&);
friend vector<T> operator+<>(const vector<T>&, const vector<T>&);
};
template<typename T>
vector<T> operator+(const vector<T>& lhs, const vector<T>& rhs)
{
vector<T> result(lhs.size_);
for (unsigned long i = 0; i != result.size_; i++)
{
result.pointer_[i] = lhs.pointer_[i] + rhs.pointer_[i];
}
return result;
}
The constructor vector(const A& size, const T& value) operates as expected, returning a vector with size elements initialized to value. operator= appears to be working, as well. When I try something like this, however, my program doesn't perform as expected:
#include <iostream>
#include "vector.h"
int main()
{
vector<int> test(5, 2); // Create a vector with five elements initialized to 2.
vector<int> test2(5, 3); // Create a vector with five elements initialized to 3.
std::cout << test.size() // Prints 5, as expected.
std::cout << test2.size() // Prints 5, as expected.
vector<int> try_result = test + test2;
std::cout << try_result.size() // Prints 0--why?
}
My question: if operator+ returns a copy of result (and not by reference, a problem that originally existed in my code), why does it appear that try_result still does not point to the proper location in the heap?
EDIT: Adding the constructor code (I've tested this, and it seems to work, but maybe for the wrong reasons):
template<typename T> template<typename A>
vector<T>::vector(const A& size)
{
this->pointer_ = new T[size];
this->size_ = size;
}
template<typename T> template<typename A>
vector<T>::vector(const A& size, const T& initial_value)
{
this->pointer_ = new T[size];
this->size_ = size;
for (unsigned long i = 0; i != this->size_; i++)
{
pointer_[i] = initial_value;
}
}
EDIT2: Adding the copy constructor.
template<typename T>
vector<T>::vector(const vector<T>& replicate_vector)
{
delete[] this->pointer_;
this->pointer_ = new T[replicate_vector.size_];
this->size_ = replicate_vector.size_;
for (unsigned long i = 0; i != this->size_; i++)
{
this->pointer_[i] = replicate_vector.pointer_[i];
}
}
I have a template class for which I'm overloading operator+, but need it to potentially return a different data type than what the class is instantiated for. For example, the following snippet performs the standard mathematical definition of either vector*vector (inner product), vector*scalar, or scalar*vector. To be specific, let's say I have a Vector<int> and the scalar is of type double -- I want to return a double from the "vector*scalar" operator+ function.
I'm pretty sure I'm missing some template<class T> statements for the friend functions(?), but this snippet isn't meant to compile.
template<class T>
class Vector
{
private:
std::vector<T> base;
public:
friend Vector operator*(const Vector& lhs, const Vector& rhs); // inner product
Vector<T> operator*(const T scalar); // vector*scalar
friend Vector operator*(const T scalar, const Vector& rhs); // scalar*vector
};
template<class T>
Vector<T> operator*(const Vector<T>& lhs, const Vector<T>& rhs) // inner product
{
assert( lhs.base.size() == rhs.base.size() );
Vector result;
result.base.reserve(lhs.base.size());
std::transform( lhs.base.begin(), lhs.base.end(), rhs.base.begin(), std::back_inserter(result.base), std::multiplies<T>() );
return result;
}
template<class T>
Vector<T> Vector<T>::operator*(const T scalar) // vector*scalar
{
Vector result;
result.base.reserve(base.size());
std::transform( base.begin(), base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );
return result;
}
template<class T>
Vector<T> operator*(const T scalar, const Vector<T>& rhs) // scalar*vector
{
Vector result;
result.base.reserve(rhs.base.size());
std::transform( rhs.base.begin(), rhs.base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );
return result;
}
I guess what you want is to return a Vector with the value type being the type returned by the per-component operation, which is not necessarily the type of the scalar.
For example:
Vector<int> * int -> Vector<int>
Vector<int> * double -> Vector<double>
Vector<double> * int -> Vector<double>
Vector<char> * float -> Vector<float>
etc.
For this, you should define the two input types separately, let's say T1 and T2 (and one or two of the operands is a Vector of it). You don't want to simply use the scalar type (for vector * scalar, or scalar * vector operation) as the result, otherwise it might be converted (see my 3rd example: The result would then be Vector<int>.
The above can be done using decltype to find the third (result) type.
For simplicity, define the operator as a non-member:
template<typename T1, typename T2, typename T3 = decltype(std::declval<T1>() * std::declval<T2>())>
Vector<T3> operator*(const Vector<T1>& lhs, const T2 & scalar) // inner product
{
Vector<T3> result;
//...
return result;
}
The interesting part is
T3 = decltype(std::declval<T1>() * std::declval<T2>())
Here, we find the type T3 using the other two types T1 and T2. First, we construct two values with unimportant value (the std::declval function is a helper function returning the type given as a template parameter). Then we multiply those values, but again the result is unimportant; we're only interested in the type. That's what the third part does: decltype gives you the type of the expression (without evaluating it).
The other operators can be implemented analogous.
In order to make those operators friends, you need the syntax
template<...> friend ...
as seen in Danvil's answer.
The friend declaration should look like this:
template<class S>
class Vector
{
private:
std::vector<S> base;
public:
template<class T> friend T operator*(const Vector<T>& lhs, const Vector<T>& rhs); // inner product
template<class T> friend Vector<T> operator*(const T scalar); // vector*scalar
template<class T> friend Vector<T> operator*(const T scalar, const Vector<T>& rhs); // scalar*vector
};
And the rest of the code like this:
template<class T>
T operator*(const Vector<T>& lhs, const Vector<T>& rhs) // inner product
{
assert( lhs.base.size() == rhs.base.size() );
Vector<T> result;
result.base.reserve(lhs.base.size());
std::transform( lhs.base.begin(), lhs.base.end(), rhs.base.begin(), std::back_inserter(result.base), std::multiplies<T>() );
return result;
}
template<class T>
Vector<T> operator*(const Vector<T>& lhs, const T scalar) // vector*scalar
{
return scalar*lhs;
}
template<class T>
Vector<T> operator*(const T scalar, const Vector<T>& rhs) // scalar*vector
{
Vector<T> result;
result.base.reserve(rhs.base.size());
std::transform( rhs.base.begin(), rhs.base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );
return result;
}
You can add more template parameters as such:
template<class T, class S>
Vector<S> Vector<T>::operator*(const S scalar)
and make sure you use S for the scalar type and T for the vector element type in the correct places in the function body.