Operator overloading in matrix using expression templates - c++

I have been trying to figure out expression templates since the last couple of days but haven't been able to get past this. I am building a matrix starting with the add operator. I am building using c++14.
My matrix.h looks like this:
template <typename T, std::size_t COL, std::size_t ROW>
class Matrix {
public:
using value_type = T;
Matrix() : values(COL * ROW) {}
static size_t cols() { return COL; }
static size_t rows() { return ROW; }
const T& operator()(size_t x, size_t y) const { return values[y * COL + x]; }
T& operator()(size_t x, size_t y) { return values[y * COL + x]; }
template <typename E>
Matrix<T, COL, ROW>& operator=(const E& expression) {
for (std::size_t y = 0; y != rows(); ++y) {
for (std::size_t x = 0; x != cols(); ++x) {
values[y * COL + x] = expression(x, y);
}
}
return *this;
}
private:
std::vector<T> values;
};
template <typename LHS, typename RHS>
class MatrixSum
{
public:
using value_type = typename LHS::value_type;
MatrixSum(const LHS& lhs, const RHS& rhs) : rhs(rhs), lhs(lhs) {}
value_type operator() (int x, int y) const {
return lhs(x, y) + rhs(x, y);
}
private:
const LHS& lhs;
const RHS& rhs;
};
template <typename LHS, typename RHS>
MatrixSum<LHS, RHS> operator+(const LHS& lhs, const LHS& rhs) {
return MatrixSum<LHS, RHS>(lhs, rhs);
}
Cpp file main function looks contains this:
Matrix<int,5,5>mx,my;
mx+my;
This shows the following error:
invalid operands to binary expression ('Matrix<int, 5, 5>' and 'Matrix<int, 5, 5>')
mx+my;
I have searched a lot online, but I clearly have missed something. The above code is taken from https://riptutorial.com/cplusplus/example/19992/a-basic-example-illustrating-expression-templates.
I would appreciate if some resources to understand expression templates can be shared.

Related

Use of common_type_t and enable_if for generic matrix class (via expression template)

I am writing a matrix library for generic types using expression templates.
The basic matrix class is a template class Matrix <typename Scalar, int RowSize, int ColumnSize>
which inherits from MatrixXpr< Matrix<Scalar, RowSize, ColumnSize> >
where MatrixXpr is the parent class for the expression templates "MatrixSum", "MatrixProduct" etc.
For example:
template <typename Mat, typename Rix>
class MatrixProduct : public MatrixXpr< MatrixProduct<Mat,Rix> >
{
private:
const Mat& A_;
const Rix& B_;
public:
using value_type= std::common_type_t<typename Mat::value_type, typename Rix::value_type>;
MatrixProduct(const Mat& A, const Rix& B) : A_(A), B_(B) {}
value_type operator()(int i, int j) const {
value_type out{ 0 };
for (int k = 0; k < A_.Columns(); ++k) out += A_(i, k) * B_(k, j);
return out;
}
};
The * operator is then defined outside
template <typename Mat, typename Rix>
MatrixProduct<Mat, Rix> inline const operator*(const MatrixXpr<Mat>& A, const MatrixXpr<Rix>& B)
{
return MatrixProduct<Mat, Rix>(A, B);
}
Now I wish to implement also a Scalar*Matrix class. But I fail to define the correct value_type:
template <typename Scalar, typename Mat>
class ScalarMatrixProduct : public MatrixXpr< ScalarMatrixProduct<Scalar, Mat> >
{
private:
const Scalar& A_;
const Mat& B_;
public:
using value_type = std::common_type_t<typename Mat::value_type, typename Scalar>;
ScalarMatrixProduct(const Scalar& A, const Mat& B) : A_(A), B_(B) {}
value_type operator()(int i, int j) const {
return A_ * B_(i, j);
}
};
template <typename Scalar, typename Mat>
typename std::enable_if < (!is_matrix<Scalar>::value),
ScalarMatrixProduct<Scalar, Mat > >::type const operator*(const Scalar& A, const MatrixXpr<Mat>& B)
{
return ScalarMatrixProduct<Scalar, Mat>(A, B);
}
On Mac and Linux I get an compilation error of this sort:
template argument 2 is invalid 102 | using value_type =
std::common_type_t<typename Mat::value_type, typename Scalar>;
Interestingly, it compiles on Windows.
Any hints for what's wrong would be helpful.
Thanks in advance.
Complete example:
#include <type_traits>
#include <iostream>
#include <array>
#include <initializer_list>
///////////Expression Template Base Class for CRTP
template <class MatrixClass> struct MatrixXpr {
decltype(auto) operator()(int i, int j) const {
return static_cast<MatrixClass const&>(*this)(i, j);
}
operator MatrixClass& () {
return static_cast<MatrixClass&>(*this);
}
operator const MatrixClass& () const {
return static_cast<const MatrixClass&>(*this);
}
int Rows()
{
return static_cast<MatrixClass&>(*this).Rows();
}
int Columns()
{
return static_cast<MatrixClass&>(*this).Columns();
}
int Rows() const
{
return static_cast<const MatrixClass&>(*this).Rows();
}
int Columns() const
{
return static_cast<const MatrixClass&>(*this).Columns();
}
friend int Rows(const MatrixXpr& A)
{
return A.Rows();
}
friend int Columns(const MatrixXpr& A)
{
return A.Columns();
}
};
template <typename MatrixClass>
std::ostream& operator<<(std::ostream& os, const MatrixXpr<MatrixClass>& A)
{
for (int r = 0; r < Rows(A); ++r) {
os << '[';
for (int c = 0; c < Columns(A); ++c)
os << A(r, c) << (c + 1 < Columns(A) ? " " : "");
os << "]\n";
}
return os;
}
/////////// Matrix Product
template <typename Mat, typename Rix>
class MatrixProduct : public MatrixXpr< MatrixProduct<Mat, Rix> >
{
private:
const Mat& A_;
const Rix& B_;
public:
using value_type = std::common_type_t<typename Mat::value_type, typename Rix::value_type>;
MatrixProduct(const Mat& A, const Rix& B) : A_(A), B_(B)
{
std::cout << "MatrixMatrixProduct Constructor\n";
}
int Rows() const { return A_.Rows(); }
int Columns() const { return B_.Columns(); }
value_type operator()(int i, int j) const {
value_type out{ 0 };
for (int k = 0; k < A_.Columns(); ++k) out += A_(i, k) * B_(k, j);
return out;
}
};
/////////// Scalar Matrix Product
template <typename Scalar, typename Mat>
class ScalarMatrixProduct : public MatrixXpr< ScalarMatrixProduct<Scalar, Mat> >
{
private:
const Scalar& A_;
const Mat& B_;
public:
using value_type = std::common_type_t<typename Mat::value_type, typename Scalar>;
ScalarMatrixProduct(const Scalar& A, const Mat& B) : A_(A), B_(B) {
std::cout << "ScalarMatrixProduct Constructor\n";
}
int Rows() const { return B_.Rows(); }
int Columns() const { return B_.Columns(); }
value_type operator()(int i, int j) const {
return A_ * B_(i, j);
}
};
//The following two functions are Helpers for initializing an array.
//Source: https://stackoverflow.com/a/38934685/6176345
template<typename T, std::size_t N, std::size_t ...Ns>
std::array<T, N> make_array_impl(
std::initializer_list<T> list,
std::index_sequence<Ns...>)
{
return std::array<T, N>{ *(list.begin() + Ns) ... };
}
template<typename T, std::size_t N>
std::array<T, N> make_array(std::initializer_list<T> list) {
if (N > list.size())
throw std::out_of_range("Initializer list too small.");
return make_array_impl<T, N>(list, std::make_index_sequence<N>());
}
/////////// Matrix class
template <typename Scalar, int RowSize, int ColumnSize = RowSize>
class Matrix : public MatrixXpr< Matrix<Scalar, RowSize, ColumnSize> >
{
std::array<Scalar, RowSize* ColumnSize> data_;
public:
using value_type = Scalar;
const static int rows_ = RowSize;
const static int columns_ = ColumnSize;
int Rows() const { return rows_; }
int Columns() const { return columns_; }
Matrix() : data_{ Scalar(0) } {};
Matrix(const Matrix& other) = default;
Matrix(Matrix&& other) = default;
Matrix& operator=(const Matrix& other) = default;
Matrix& operator=(Matrix&& other) = default;
~Matrix() = default;
Matrix(std::initializer_list<Scalar> data) : data_(make_array<Scalar, RowSize* ColumnSize>(data)) {}
template <typename Source>
Matrix& operator=(const MatrixXpr<Source>& source)
{
for (int i = 0; i < rows_; ++i)
for (int j = 0; j < columns_; ++j)
data_[MatrixIndex(i, j)] = source(i, j);
return *this;
}
template <typename Source>
Matrix(const MatrixXpr<Source>& source)
{
for (int i = 0; i < rows_; ++i)
for (int j = 0; j < columns_; ++j)
data_[MatrixIndex(i, j)] = source(i, j);
}
Scalar& operator()(int i, int j) {
return data_[MatrixIndex(i, j)];
}
const Scalar& operator()(int i, int j) const {
return data_[MatrixIndex(i, j)];
}
private:
inline static int MatrixIndex(int i, int j)
{
return i * columns_ + j;
}
};
/////////// Multiplication operators
template <typename Mat, typename Rix>
MatrixProduct<Mat, Rix> inline const operator*(const MatrixXpr<Mat>& A, const MatrixXpr<Rix>& B)
{
std::cout << "Matrix Matrix Multiplication\n";
return MatrixProduct<Mat, Rix>(A, B);
}
template <typename Scalar, typename Mat>
typename std::enable_if_t<!std::is_base_of_v<MatrixXpr<Scalar>, Scalar>,
ScalarMatrixProduct<Scalar, Mat >> const operator*(const Scalar& A, const MatrixXpr<Mat>& B)
{
return ScalarMatrixProduct<Scalar, Mat>(A, B);
}
/////////// Failing example
int main()
{
Matrix<int, 2, 2> m = { 1,0,0,1 };
auto n = 3 * m;
std::cout << n;
std::cout << m * n;
//std::cout << n * m; // Error
return 0;
}
Edit:
The above code originally had two problems.
The first one is that my type checking failed to see which overload of the *operator was being used. The above implementation with std::is_base_of_v<MatrixXpr<Scalar>, Scalar> fixed it and is is working correctly.
I do not know why this old code did not work. Here is the old version:
template <typename T>
struct is_matrix : std::false_type {};
template <typename T>
struct is_matrix<const T> : is_matrix<T> {};
template <typename MatrixClass>
struct is_matrix<MatrixXpr<MatrixClass> > : std::true_type {};
template <typename Scalar, typename Mat>
typename std::enable_if < (!is_matrix<Scalar>::value),
ScalarMatrixProduct<Scalar, Mat > >::type const operator*(const Scalar& A, const MatrixXpr<Mat>& B)
{
std::cout << "Scalar Matrix Multiplication\n";
return ScalarMatrixProduct<Scalar, Mat>(A, B);
}

C++ - How to program functions that work on temporaries and don't allocate

I am trying to implement a fixed size array class that will represent small size vectors.
I wanted to have typical vector operations defined, like multiplication by scalar and sum with another vector.
The problem is I cannot get the same performance with these two codes:
for (size_t i = 0; i < N; ++i)
vout[i] = (k[0][i] + 2*k[1][i] + 2*k[2][i] + k[3][i])/6;
// vs
vout = (k[0] + 2.0*k[1] + 2.0*k[2] + k[3])/6.0;
The reason is that the second option is creating more arrays in the process, while the first adds in place.
I would like to know if there is a way to write a function that operates on temporaries (r-value references) so that a sum is performed over the temporary, without allocating an extra vector.
My current code:
template<class T, int N>
class SVec {
public:
inline T& operator[](int i) { return mdata[i]; }
inline const T operator[](size_t i) const { return mdata[i]; }
inline T* data() { return mdata; }
inline T const* data() const { return mdata; }
inline SVec& operator+=(const SVec& rhs) {
for (size_t i = 0; i < N; ++i) mdata[i] += rhs.mdata[i];
return *this;
}
inline SVec& operator-=(const SVec& rhs) {
for (size_t i = 0; i < N; ++i) mdata[i] -= rhs.mdata[i];
return *this;
}
inline SVec& operator*=(T rhs) {
for (size_t i = 0; i < N; ++i) mdata[i] *= rhs;
return *this;
}
inline SVec& operator/=(T rhs) {
for (size_t i = 0; i < N; ++i) mdata[i] /= rhs;
return *this;
}
inline SVec& fma(const SVec& x, T y) {
for (size_t i = 0; i < N; ++i) mdata[i] += x[i]*y;
return *this;
}
inline SVec&& operator+(const SVec& rhs) && {
for (size_t i = 0; i < N; ++i) mdata[i] += rhs.mdata[i];
return std::move(*this);
}
inline SVec&& operator*(T rhs) && {
for (size_t i = 0; i < N; ++i) mdata[i] *= rhs;
return std::move(*this);
}
inline SVec&& operator/(T rhs) && {
for (size_t i = 0; i < N; ++i) mdata[i] /= rhs;
return std::move(*this);
}
private:
T mdata[N];
};
template<typename T, int N>
inline SVec<T, N> operator+(SVec<T, N> lhs, const SVec<T, N>& rhs) {
return lhs += rhs;
}
// Tried:
// template<typename T, int N>
// inline SVec<T, N>&& operator+(SVec<T, N>&& lhs, const SVec<T, N>& rhs) {
// lhs += rhs;
// return lhs;
// }
// template<typename T, int N>
// inline SVec<T, N>&& operator+(const SVec<T, N>& rhs, SVec<T, N>&& lhs) {
// lhs += rhs;
// return lhs;
// }
// template<typename T, int N>
// inline SVec<T, N>&& operator+(SVec<T, N>&& lhs, SVec<T, N>&& rhs) {
// lhs += rhs;
// return lhs;
// }
template<typename T, int N>
inline SVec<T, N> operator-(SVec<T, N> lhs, const SVec<T, N>& rhs) {
return lhs -= rhs;
}
template<typename T, int N>
inline SVec<T, N> operator*(SVec<T, N> lhs, T rhs) {
return lhs *= rhs;
}
tem
plate<typename T, int N>
inline SVec<T, N> operator*(T rhs, SVec<T, N> lhs) {
return lhs *= rhs;
}
template<typename T, int N>
inline SVec<T, N> operator/(SVec<T, N> lhs, T rhs) {
return lhs /= rhs;
}
template<typename T, int N>
inline SVec<T, N> operator/(T rhs, SVec<T, N> lhs) {
return lhs /= rhs;
}
template<typename T, int N>
inline SVec<T, N> fma(const SVec<T, N>& x, T y, SVec<T, N> z) {
return z.fma(x, y);
}
template<int N>
using DoubleVec = SVec<double, N>;
If I understood you correctly, you are trying to return the object which is modified on the original copy. Which cannot be done on a standalone operator+.
However there is the concept of return value optimization which may apply to your compiler depending on the usage, if you immediately return the result from a function which returns by value, it is possible that the compiler will optimize it not to store it on a temporary:
Return value optimization
I can see that your standalone operator+ only accepts the same type, so you can also make a similar operator+(...)& for as a class member and that can return itself. But this will bring more problems as shown below:
inline SVec& operator+(const SVec& rhs)& {
for (size_t i = 0; i < N; ++i) mdata[i] += rhs.mdata[i];
return *this;
}
This will not work correctly when you have a statement like this, but it will not create a new copy.
SVec<int, 2> s1;
SVec<int, 2> s2;
SVec<int, 2> s3;
s3 = s1 + s2;

c++ Force implicit conversion on pass as argument

I have problem with implicit conversions in C++.
I'm trying to create some Expression template for vector arithmetics (I know that same libraries already exists. I'm just learning C++ so I wanted to try something with templates).
I would like to create class Vector, that is able to compute like this:
simd::test::Vector<char, 5> a;
simd::test::Vector<short, 5> b;
auto ret = a + b + a + b;
, where on output would be Vector of shorts becouse short is bigger type than char.
Right now, I have class that is able to adds vectors of same data types. For different types I have to call explicit conversion:
//simd::test::Vector<short, 5>(a)
auto ret = simd::test::Vector<short, 5>(a) + b + simd::test::Vector<short, 5>(a) + b;
Is possible to implicit convert Vector before pass into function "operator+()"? Here is my code of Vector:
#pragma once
#include <type_traits>
namespace simd {
namespace test {
template<typename R, std::size_t Dim,
typename std::enable_if<std::is_arithmetic<R>::value>::type* = nullptr
>
class Vector_expression {
public:
static constexpr std::size_t size = Dim;
virtual const R operator[] (std::size_t index) const = 0;
virtual ~Vector_expression() = default;
};
template<typename T, std::size_t Dim>
class Vector final : public Vector_expression<T, Dim> {
private:
T data[Dim];
public:
Vector() = default;
template<typename R>
Vector(const Vector_expression<R, Dim> &obj) {
for(std::size_t index = 0; index < Dim; ++index) {
data[index] = obj[index];
}
}
template<typename R>
Vector(Vector_expression<R, Dim> &&obj) {
for(std::size_t index = 0; index < Dim; ++index) {
data[index] = obj[index];
}
}
template<typename R>
Vector<T, Dim> & operator=(const Vector_expression<R, Dim> &obj) {
for(std::size_t index = 0; index < Dim; ++index) {
data[index] = obj[index];
}
return (*this);
}
template<typename R>
Vector<T, Dim> & operator=(Vector_expression<R, Dim> && obj) {
for(std::size_t index = 0; index < Dim; ++index) {
data[index] = obj[index];
}
return (*this);
}
virtual const T operator[] (std::size_t index) const override {
return data[index];
}
T & operator[] (std::size_t index) {
return data[index];
}
virtual ~Vector() = default;
};
template<typename E1, typename E2, typename R, std::size_t Dim>
class Vector_sum final : public Vector_expression<R, Dim> {
private:
const E1 & _lhs;
const E2 & _rhs;
public:
Vector_sum() = delete;
Vector_sum(const E1 & lhs, const E2 & rhs) :
_lhs(lhs),
_rhs(rhs)
{}
virtual const R operator[] (std::size_t index) const override {
return _lhs[index] + _rhs[index];
}
virtual ~Vector_sum() = default;
};
template<typename R, std::size_t Dim>
Vector_sum<Vector_expression<R, Dim>, Vector_expression<R, Dim>, R, Dim> operator+ (const Vector_expression<R, Dim> & lhs, const Vector_expression<R, Dim> & rhs) {
return {lhs, rhs};
}
}
}
Just define an operator+ that allows different argument types. The one catch is determining the element type of the resulting sum. Probably the best option is to use whatever the result of adding two elements is. One way to write this type is:
decltype(std::declval<const R1>() + std::declval<const R2>())
Or if you know the types are built-in arithmetic types, that would be the same as
std::common_type_t<R1, R2>
Or using a trailing return type, we can take advantage of the function parameters to shorten the std::declval expressions:
template<typename R1, typename R2, std::size_t Dim>
auto operator+ (const Vector_expression<R1, Dim> & lhs,
const Vector_expression<R2, Dim> & rhs)
-> Vector_sum<Vector_expression<R1, Dim>, Vector_expression<R2, Dim>,
decltype(lhs[0] + rhs[0]), Dim>
{
return {lhs, rhs};
}
It could be done using templates and std::common_type, something like this:
template<typename T1, typename T2, size_t S>
simd::test::Vector<typename std::common_type<T1, T2>::type, S>
operator+(simd::test::Vector<T1, S> const& v1,
simd::test::Vector<T2, S> const& v2)
{
// TODO: Implementation...
}

Assigning to expression templates

I have little c++ experience, but now I need to look at some code that uses expression templates a lot, so I am reading chapter 18 of the book << C++ Templates: The Complete Guide >> and working on the example provided in the book. If you happened to have the book, the example starts from pp 328, with all the contextual information.
My code works fine until I want to add the support for subvector indexing (pp 338), I could not get the assignment to work, g++ gives the following error:
error: binding ‘const value_type {aka const double}’ to reference of type ‘double&’ discards qualifiers
return v[vi[idx]];
I have no idea what's going on, am I assigning to a constant object? How do I make this work? Here is my code:
#include <iostream>
#include <vector>
template<typename T>
class ET_Scalar {
private:
const T& s;
public:
ET_Scalar(const T& v) :
s(v) {}
T operator[](size_t) const
{
return s;
}
size_t size() const
{
return 0; // Zero means it's a scalar
}
};
template<typename T, typename V, typename VI>
class ET_SubVec {
private:
const V& v;
const VI& vi;
public:
ET_SubVec(const V& a, const VI& b) :
v(a), vi(b) {}
const T operator[] (size_t idx) const
{
return v[vi[idx]];
}
T& operator[] (size_t idx)
{
return v[vi[idx]];
}
size_t size() const
{
return vi.size();
}
};
// Using std::vector as storage
template<typename T, typename Rep = std::vector<T>>
class ET_Vector {
private:
Rep expr_rep;
public:
// Create vector with initial size
explicit ET_Vector(size_t s) :
expr_rep(s) {}
ET_Vector(const Rep& v) :
expr_rep(v) {}
ET_Vector& operator=(const ET_Vector& v)
{
for (size_t i = 0; i < v.size(); i++)
expr_rep[i] = v[i];
return *this;
}
template<typename T2, typename Rep2>
ET_Vector& operator=(const ET_Vector<T2, Rep2>& v)
{
for (size_t i = 0; i < v.size(); i++)
expr_rep[i] = v[i];
return *this;
}
size_t size() const
{
return expr_rep.size();
}
const T operator[](size_t idx) const
{
return expr_rep[idx];
}
T& operator[](size_t idx)
{
return expr_rep[idx];
}
template<typename T2, typename Rep2>
ET_Vector<T, ET_SubVec<T, Rep, Rep2>> operator[](const ET_Vector<T2, Rep2>& vi)
{
return ET_Vector<T, ET_SubVec<T, Rep, Rep2>>(ET_SubVec<T, Rep, Rep2>(expr_rep, vi.rep()));
}
template<typename T2, typename Rep2>
const ET_Vector<T, ET_SubVec<T, Rep, Rep2>> operator[](const ET_Vector<T2, Rep2>& vi) const
{
return ET_Vector<T, ET_SubVec<T, Rep, Rep2>>(ET_SubVec<T, Rep, Rep2>(expr_rep, vi.rep()));
}
// Return what the vector currently represents
const Rep& rep() const
{
return expr_rep;
}
Rep& rep()
{
return expr_rep;
}
};
template<typename T>
class ET_Traits {
public:
typedef const T& ExprRef;
};
template<typename T>
class ET_Traits<ET_Scalar<T>> {
public:
typedef ET_Scalar<T> ExprRef;
};
template<typename T, typename LHS, typename RHS>
class ET_Add {
private:
typename ET_Traits<LHS>::ExprRef lhs;
typename ET_Traits<RHS>::ExprRef rhs;
public:
ET_Add(const LHS& l, const RHS& r) :
lhs(l), rhs(r) {}
T operator[](size_t idx) const
{
return lhs[idx] + rhs[idx];
}
size_t size() const
{
return (lhs.size() != 0) ? lhs.size() : rhs.size();
}
};
template<typename T, typename LHS, typename RHS>
class ET_Mul {
private:
typename ET_Traits<LHS>::ExprRef lhs;
typename ET_Traits<RHS>::ExprRef rhs;
public:
ET_Mul(const LHS& l, const RHS& r) :
lhs(l), rhs(r) {}
T operator[](size_t idx) const
{
return lhs[idx] * rhs[idx];
}
size_t size() const
{
return (lhs.size() != 0) ? lhs.size() : rhs.size();
}
};
// Vector + Vector
template<typename T, typename LHS, typename RHS>
ET_Vector<T, ET_Add<T, LHS, RHS>>
operator+(const ET_Vector<T, LHS>& a, const ET_Vector<T, RHS>& b)
{
return ET_Vector<T, ET_Add<T, LHS, RHS>>(ET_Add<T, LHS, RHS>(a.rep(), b.rep()));
}
// Scalar + Vector
template<typename T, typename RHS>
ET_Vector<T, ET_Add<T, ET_Scalar<T>, RHS>>
operator+(const T& s, const ET_Vector<T, RHS>& b)
{
return ET_Vector<T, ET_Add<T, ET_Scalar<T>, RHS>>(ET_Add<T, ET_Scalar<T>, RHS>(ET_Scalar<T>(s), b.rep()));
}
// Vector .* Vector
template<typename T, typename LHS, typename RHS>
ET_Vector<T, ET_Mul<T, LHS, RHS>>
operator*(const ET_Vector<T, LHS>& a, const ET_Vector<T, RHS>& b)
{
return ET_Vector<T, ET_Mul<T, LHS, RHS>>(ET_Mul<T, LHS, RHS>(a.rep(), b.rep()));
}
//Scalar * Vector
template<typename T, typename RHS>
ET_Vector<T, ET_Mul<T, ET_Scalar<T>, RHS>>
operator*(const T& s, const ET_Vector<T, RHS>& b)
{
return ET_Vector<T, ET_Mul<T, ET_Scalar<T>, RHS>>(ET_Mul<T, ET_Scalar<T>, RHS>(ET_Scalar<T>(s), b.rep()));
}
template<typename T>
void print_vec(const T& e)
{
for (size_t i = 0; i < e.size(); i++) {
std::cout << e[i] << ' ';
}
std::cout << '\n';
return;
}
int main()
{
size_t N = 16;
ET_Vector<double> x(N);
ET_Vector<double> y(N);
ET_Vector<double> z(N);
ET_Vector<int> idx(N / 2);
// Do not use auto z = [expr] here! Otherwise the type of z will still be a
// container, and evaluation won't happen until later. But the compiler
// will optimize necessary information away, causing errors.
z = (6.5 + x) + (-2.0 * (1.25 + y));
print_vec(z);
for (int i = 0; i < 8; i++)
idx[i] = 2 * i;
z[idx] = -1.0 * z[idx];
print_vec(z);
return 0;
}
Sorry about its length, I've failed to create a minimal (not) working example.

Cannot convert from *const to & in += operator [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I was staring at this all night before I decided to give up and go to sleep - a few hours into it again today, I still don't have it. I am unable to figure out how to change the const-ness and parameters to correctly return (on the operator+=). Any help?
The error pops up at the return this statement in the operator+= overload.
#include <iostream>
#include <vector>
template <typename T> class Matrix {
private:
unsigned rows, cols;
public:
Matrix();
~Matrix();
Matrix(const Matrix<T>& rhs);
Matrix(unsigned _rows, unsigned _cols);
std::vector<std::vector<T>> matrix;
Matrix<T>& operator=(Matrix<T> rhs);
//Matrix mathematical operations
Matrix<T> operator+(const Matrix<T>& rhs);
Matrix<T>& operator+=(const Matrix<T>& rhs);
// Access the individual elements
T& operator()(const unsigned& row, const unsigned& col);
const T& operator()(const unsigned& row, const unsigned& col) const;
// Access the row and column sizes
unsigned get_rows() const;
unsigned get_cols() const;
void swap(Matrix<T>& rhs);
};
template<typename T>
Matrix<T>::Matrix() {}
template<typename T>
Matrix<T>::~Matrix() {}
// Parameter Constructor
template<typename T>
Matrix<T>::Matrix(unsigned _rows, unsigned _cols) {
matrix.resize(_rows);
for (unsigned i = 0; i < _rows; i++)
matrix[i].resize(_cols, 1); // change back to 0 after debug
rows = _rows;
cols = _cols;
}
template<typename T>
Matrix<T>& Matrix<T>::operator=(Matrix<T> rhs) {
swap(rhs);
return *this;
}
template<typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>& rhs) {
Matrix<T> result(*this);
result += rhs;
return result;
}
template<typename T>
Matrix<T>& Matrix<T>::operator+=(const Matrix<T>& rhs) {
for (unsigned i = 0; i < rows; i++) {
for (unsigned j = 0; j < cols; j++) {
this->matrix[i][j] += rhs(i, j);
}
}
return this; // error pops up here
}
// Access the individual elements
template<typename T>
T& Matrix<T>::operator()(const unsigned& row, const unsigned& col) {
return this->matrix[row][col];
}
// Access the individual elements (const)
template<typename T>
const T& Matrix<T>::operator()(const unsigned& row, const unsigned& col) const{
return this->matrix[row][col];
}
// Get the number of rows of the matrix
template<typename T>
unsigned Matrix<T>::get_rows() const {
return this->rows;
}
//Get the number of columns of the matrix
template<typename T>
unsigned Matrix<T>::get_cols() const {
return this->cols;
}
template<typename T>
void Matrix<T>::swap(Matrix<T>& rhs) {
using std::swap;
swap(this->rows, rhs.rows);
swap(this->cols, rhs.cols);
swap(this->matrix, rhs.matrix);
}
// for debugging
template<typename T>
void print_matrix(Matrix<T>& matrix) {
for (int i = 0; i < matrix.get_rows(); i++) {
for (int j = 0; j < matrix.get_cols(); j++) {
std::cout << matrix(i, j) << " ";
}
std::cout << " " << std::endl;
}
}
int main(int argc, char **argv) {
Matrix<double> matrix1(5, 5);
Matrix<double> matrix2(5, 5);
// Start testing
Matrix<double> matrix3 = matrix1 + matrix2;
print_matrix(matrix1);
std::getchar();
return 0;
}
In the += operator, you probably want:
Matrix<T>& Matrix<T>::operator+=(const Matrix<T>& rhs) {
//....
return *this;
//^^
}
The linker error is because you did not define:
Matrix(const Matrix<T>& rhs);