SEGFAULT in CRTP arrays of matrices - c++

I'm trying to construct an array/matrix library using the Curiously Recurring Template Pattern (CRTP). I have arrays and matrices working well. But when using arrays of matrices, eg, TN_Array<TN_Matrix<double 2,3> > some expressions compile but segfault on running. The code to minimally present what is and isn't working is quite long, but I've worked hard to minimize it, see below. I would appreciate any insight into how to rectify this problem! Thanks, Ben.
PS git repo of minimal example at https://github.com/bmclean75/Tungsten2 for your convenience, it is the same as the code listed below.
Debugger call stack:
AddOp::calc<2, 3, double>(const double & A, const TN_Matrix<double, 2, 3> & B, int i) (/home/ben/code/new/Tungsten2_example/TN_StructAddOp.h:23)
MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double>::calc(const MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double> * const this, int i) (/home/ben/code/new/Tungsten2_example/TN_ExprTemp.h:25)
AddOp::calc<double, double, AddOp, TN_Matrix<double, 2, 3>, 2, 3>(const double & A, const MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double> & B, int i) (/home/ben/code/new/Tungsten2_example/TN_StructAddOp.h:31)
MatBinExpr<double, AddOp, MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double>, 2, 3, double>::calc(const MatBinExpr<double, AddOp, MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double>, 2, 3, double> * const this, int i) (/home/ben/code/new/Tungsten2_example/TN_ExprTemp.h:25)
TN_Matrix<double, 2, 3>::operator=<MatBinExpr<double, AddOp, MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double>, 2, 3, double> >(TN_Matrix<double, 2, 3> * const this, const MatBinExpr<double, AddOp, MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double>, 2, 3, double> & expression) (/home/ben/code/new/Tungsten2_example/TN_Matrix.h:25)
TN_Array<TN_Matrix<double, 2, 3> >::operator=<ArrMatBinExpr<double, AddOp, ArrMatBinExpr<double, AddOp, TN_Array<TN_Matrix<double, 2, 3> >, 2, 3, MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double> >, 2, 3, MatBinExpr<double, AddOp, MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double>, 2, 3, double> > >(TN_Array<TN_Matrix<double, 2, 3> > * const this, const ArrMatBinExpr<double, AddOp, ArrMatBinExpr<double, AddOp, TN_Array<TN_Matrix<double, 2, 3> >, 2, 3, MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double> >, 2, 3, MatBinExpr<double, AddOp, MatBinExpr<double, AddOp, TN_Matrix<double, 2, 3>, 2, 3, double>, 2, 3, double> > & expression) (/home/ben/code/new/Tungsten2_example/TN_Array.h:38)
main() (/home/ben/code/new/Tungsten2_example/TN_AddOpTests.cpp:25)
#include "TN_Matrix.h"
#include "TN_Array.h"
#include "TN_ExprTemp.h"
#include "TN_StructAddOp.h"
#include "TN_OperatorAdd.h"
int main(void)
{
//works flawlessly:
TN_Matrix<double,2,3> mat1;
TN_Matrix<double,2,3> mat_calc_answer;
mat_calc_answer = 7.0 + (10.0 + mat1);
//also works flawlessly:
TN_Array<double> arr1(2,3,4);
TN_Array<double> arr_calc_answer(2,3,4);
arr_calc_answer = 7.0 + (10.0 + arr1);
TN_Array<TN_Matrix<double,2,3> > arrmat1(3,1,2);
TN_Array<TN_Matrix<double,2,3> > arrmat_calc_answer(3,1,2);
//works flawlessly:
arrmat_calc_answer = (10.0 + arrmat1);
//compiles but segfaults:
arrmat_calc_answer = 7.0 + (10.0 + arrmat1);
return (0);
}
#ifndef TN_MATRIX
#define TN_MATRIX
#include <vector>
using namespace std;
template <class datatype, int nrows, int ncols> class TN_Matrix{
protected:
int m_nrows, m_ncols; //matrix size
int m_nt; //total number of cells
vector<datatype> m_data; //matrix cell data
public:
//constructor
TN_Matrix() : m_nrows(nrows), m_ncols(ncols), m_nt(m_nrows*m_ncols), m_data(m_nt){};
//assignment by expression
template<typename expr>
TN_Matrix<datatype,nrows,ncols> &operator=(const expr &expression){
for(int i=0;i < m_nt;++i){
m_data[i] = expression.calc(i);
}
return *this;
}
//calc(index)
inline const datatype & calc(int i) const{
return m_data[i];
};
};
#endif //TN_Matrix
#ifndef TN_ARRAY
#define TN_ARRAY
#include <vector>
template <class datatype>
class TN_Array {
protected:
int m_nx, m_ny, m_nz; //array size
int m_nt; //total number of cells
vector<datatype> m_data; //array data
public:
//constructor
TN_Array(int nx = 1, int ny = 1, int nz = 1){
m_nx = nx;
m_ny = ny;
m_nz = nz;
m_nt = nx*ny*nz;
m_data.resize(m_nt);
};
//operator = expression
template<typename expr>
TN_Array<datatype> &operator = (const expr &expression){
#ifdef TN_PARALLELARRAY
#pragma omp parallel for
#endif
for(int i=0; i < m_nt; ++i){
m_data[i] = expression.calc(i);
}
return *this;
}
//calc(i) indexing
inline const datatype &calc(int i) const {
return m_data[i];
};
};
#endif //TN_ARRAY
#ifndef TN_EXPRTEMP
#define TN_EXPRTEMP
using namespace std;
template<class LHS, class Op, class RHS, int nrows, int ncols, class RtnType>
class MatBinExpr
{
protected :
const LHS & left_;
const RHS & right_;
const int nrows_, ncols_;
public :
//empty constructor will be optimized away, but triggers
//type identification needed for template expansion
MatBinExpr(const LHS & leftArg, const RHS & rightArg) : left_(leftArg),
right_(rightArg), nrows_(nrows), ncols_(ncols)
{};
//empty destructor will be optimized away
~MatBinExpr(){};
//calculate value of expression at specified index by recursing
inline RtnType calc(int i) const{
return Op::calc(left_, right_, i);
};
};
template<class LHS, class Op, class RHS, class RtnType>
class ArrBinExpr
{
protected :
const LHS & left_;
const RHS & right_;
public :
//empty constructor will be optimized away, but triggers
//type identification needed for template expansion
ArrBinExpr(const LHS & leftArg, const RHS & rightArg) : left_(leftArg),
right_(rightArg)
{};
//empty destructor will be optimized away
~ArrBinExpr(){};
//calculate value of expression at specified index by recursing
inline RtnType calc(int i) const{
return Op::calc(left_, right_, i);
};
};
template<class LHS, class Op, class RHS, int nrows, int ncols, class RtnType>
class ArrMatBinExpr
{
protected :
const LHS & left_;
const RHS & right_;
const int nrows_, ncols_;
public :
//empty constructor will be optimized away, but triggers
//type identification needed for template expansion
ArrMatBinExpr(const LHS & leftArg, const RHS & rightArg) : left_(leftArg),
right_(rightArg), nrows_(nrows), ncols_(ncols)
{};
//empty destructor will be optimized away
~ArrMatBinExpr(){};
//calculate value of expression at specified index by recursing
inline RtnType calc(int i) const{
return Op::calc(left_, right_, i);
};
};
#endif //TN_EXPRTEMP
#ifndef TN_STRUCTADDOP
#define TN_STRUCTADDOP
/*
All operators are of the pattern:
template<any templated params>
static inline returntype calc(const type1 &A, const type2 &B, int i){
return A _OPSYMB B.calc(i);
}
*/
struct AddOp
{
//LHS datatype:
//*************
//datatype op Matrix
template <int nrows, int ncols, class datatype>
static inline datatype calc(const datatype &A,
const TN_Matrix<datatype, nrows, ncols> &B,
int i)
{
return A + B.calc(i);
}
//datatype op MatBinExpr
template <class datatype, class lhs, class op, class rhs, int nrows, int ncols>
static inline datatype
calc(const datatype &A, const MatBinExpr<lhs, op, rhs, nrows, ncols, datatype> &B, int i)
{
return A + B.calc(i);
}
//datatype op Array
template <class datatype>
static inline datatype calc(const datatype &A,
const TN_Array<datatype> &B,
int i)
{
return A + B.calc(i);
}
//datatype op ArrBinExpr
template <class datatype, class lhs, class op, class rhs>
static inline datatype
calc(const datatype &A, const ArrBinExpr<lhs, op, rhs, datatype> &B, int i)
{
return A + B.calc(i);
}
//datatype op array<matrix>
template <class datatype, int nrows, int ncols>
static inline MatBinExpr<datatype, AddOp, TN_Matrix<double, nrows, ncols>, nrows, ncols, double>
calc( const datatype &A,
const TN_Array<TN_Matrix<datatype, nrows, ncols> > &B,
int i)
{
return A + B.calc(i);
}
//datatype op ArrMatBinExpr
//compiles, segfaults
template<class datatype, class lhs, class op, class rhs,int nrows, int ncols, class rtntype>
static inline MatBinExpr<datatype,AddOp,rtntype,nrows,ncols,datatype >
calc( const datatype &A,
const ArrMatBinExpr<lhs,op,rhs,nrows,ncols,rtntype> &B,
int i)
{
return A + B.calc(i);
}
};
#endif //STRUCTADDOP
#ifndef TN_OPERATORADD
#define TN_OPERATORADD
/*
All operators are of the pattern:
template<any templated params>
static inline BinExpr<LHS, _OPNAME, RHS, returntype>
operator _OPSYMB(const LHS &A, const RHS &B){
return BinExpr<LHS, _OPNAME, RHS> (A,B);
}
*/
//LHS datatype:
//*************
//datatype op Matrix
template<int nrows, int ncols, class datatype>
static inline MatBinExpr<datatype,AddOp,TN_Matrix<datatype,nrows,ncols>,nrows,ncols,datatype>
operator +(const datatype &A, const TN_Matrix<datatype, nrows, ncols> &B){
return MatBinExpr<datatype,AddOp,
TN_Matrix<datatype, nrows, ncols>,nrows,ncols,datatype> (A,B);
}
//datatype op MatBinExpr
template<class lhs, class op, class rhs, int nrows, int ncols, class datatype>
static inline MatBinExpr< datatype,AddOp,
MatBinExpr<lhs,op,rhs,nrows,ncols,datatype>,nrows,ncols,datatype>
operator +(const datatype &A, const MatBinExpr<lhs,op,rhs,nrows,ncols,datatype> &B){
return MatBinExpr< datatype,AddOp,
MatBinExpr<lhs,op,rhs,nrows,ncols,datatype>,nrows,ncols,datatype> (A,B);
}
//datatype op Array
template<class datatype>
static inline ArrBinExpr<datatype,AddOp,
TN_Array<datatype>,datatype>
operator +(const datatype &A, const TN_Array<datatype> &B){
return ArrBinExpr<datatype,AddOp,
TN_Array<datatype>,datatype> (A,B);
}
//datatype op ArrBinExpr
template<class datatype, class lhs, class op, class rhs>
static inline ArrBinExpr<datatype,AddOp,
ArrBinExpr<lhs,op,rhs,datatype>,datatype>
operator +(const datatype &A, const ArrBinExpr<lhs,op,rhs,datatype> &B){
return ArrBinExpr<datatype,AddOp,
ArrBinExpr<lhs,op,rhs,datatype>,datatype> (A,B);
}
//datatype op array<matrix>
template<class datatype, int nrows, int ncols>
static inline ArrMatBinExpr<datatype,
AddOp,
TN_Array<TN_Matrix<datatype,nrows,ncols> >,
nrows, ncols,
MatBinExpr<datatype,AddOp,TN_Matrix<datatype,nrows,ncols>,nrows,ncols,datatype> >
operator +(const datatype &A, const TN_Array<TN_Matrix<datatype,nrows,ncols> > &B){
return ArrMatBinExpr< datatype,
AddOp,
TN_Array<TN_Matrix<datatype,nrows,ncols> >,
nrows, ncols,
MatBinExpr<datatype,AddOp,TN_Matrix<datatype,nrows,ncols>,nrows,ncols,datatype> > (A,B);
}
//datatype op ArrMatBinExpr
//compiles, segfaults
template<class datatype, class lhs, class op, class rhs, int nrows, int ncols, class rtntype>
static inline ArrMatBinExpr<datatype,
AddOp,
ArrMatBinExpr<lhs,op,rhs,nrows,ncols,rtntype>,
nrows, ncols,
MatBinExpr<datatype,AddOp,rtntype,nrows,ncols,datatype > >
operator +(const datatype &A, const ArrMatBinExpr<lhs,op,rhs,nrows,ncols,rtntype > &B){
return ArrMatBinExpr< datatype,
AddOp,
ArrMatBinExpr<lhs,op,rhs,nrows,ncols,rtntype>,
nrows, ncols,
MatBinExpr<datatype,AddOp,rtntype,nrows,ncols,datatype > > (A,B);
}
#endif //OPERATORADD

Related

Questions about ”operator=” and ”operator[]”

I have a question about the code below.
Why is it possible to run const auto& vec1 = vec; successfully even though my_vector& operator=(const my_vector&) = delete is defined?
Secondly, why is the &, && at the end of operator[] necessary? If I remove them, I get an error.
I understand that the & after the operator is a reference to the class itself.
Then I grasp that the ones without const are for writing.
#include <iostream>
#include <stdlib.h>
#include<vector>
template<typename T, typename Alloc = std::allocator<T>>
class my_vector
{
std::vector<T, Alloc> vec;
public:
my_vector(const my_vector&);
my_vector& operator=(const my_vector&) = delete;
my_vector(std::initializer_list<T> init) : vec{init} {}
T& operator[](std::size_t n) & { std::cout<<"&"<<std::endl; return vec[n]; }
const T& operator[](std::size_t n) const& { std::cout<<"const &"<<std::endl; return vec[n]; }
T operator[](std::size_t n) && noexcept {std::cout<<"move"<<std::endl; return std::move(vec[n]); }
};
int main()
{
my_vector<int> vec{1, 2, 3};
const auto& vec1 = vec;
vec[0] = 2; //case1 &
std::cout<<vec1[0]<<std::endl;
//vec1[0] = 1; const error
int tmp1 = vec1[0] ; //case2 const&
auto&& vec5 = my_vector<int>{1, 2, 3}[0]; //case3 move
}

Implicit conversion class templates

I am trying to implement a Matrix class with linear algebraic operations. I want to make the class available for a few value types like uint, uchar, float, double.
The header looks as follows:
template<typename T>
class Matrix{
public:
Matrix(int width, int height);
Matrix(const Matrix<T> & other);
virtual ~Matrix();
unsigned int width() const { return width_; }
unsigned int height() const { return height_; };
T * data() const { return data_ptr_; };
private:
T * data_ptr_;
unsigned int width_;
unsigned int height_;
}
The source file looks as follows.
template<typename T>
Matrix<T>::Matrix(int width, int height ): width_(width), height_(height)
{
data_ptr_ = new T[width * height];
}
template<typename T>
Matrix<T>::Matrix(const Matrix<T> & other): Matrix(other.width(), other.height() )
{
memcpy(data_ptr_, other.data(), width_ * height_ * sizeof(T);
}
template<typename T>
Matrix<T>::~Matrix()
{
delete []data_ptr_;
}
template class Matrix<double>;
template class Matrix<float>;
...
Now I want to define an operator + which will return a Matrix of the type which an ordinary c++ conversion does when adding two values, i.e.
Matrix<double> + Matrix<float> => Matrix<double>
Matrix<int> + Matrix<float> => Matrix<float>
and I want to be able to do this without explicit conversions. For example
Matrix<float> float_matrix(10,20);
Matrix<int> int_matrix(10,20);
auto sum_matrix = float_matrix + int_matrix;
so the sum should have type float.
I tried 2 methods with no success, however.
Method 1
Define operator + as
//inside class definition
Matrix<T> operator+(const Matrix<T> &other) const;
and define implicit constructors like
//inside the class declaration
template<typename K>
Matrix(const Matrix<K> & other);
and instantiate them only in the obvious hierarchical order:
uchar-> uint->float->double, however I still have to manually cast operands of different types.
Method 2
Define operator + as
//inside the class declaration
template<typename K, typename R>
Matrix<R> operator+(const Matrix<K> &other) const;
and write specializations for each case, however, I could not get the compiler to correctly deduce the template arguments.
Neither of methods seem to be correct.
Can anyone point me a direction?
You can use method 3 and use C++11's auto return type deduction to figure out the type for you. Using
template<typename K>
auto operator+(const Matrix<K> &other) const -> Matrix<decltype(std::declval<T>() + std::declval<K>())>;
This says that the matrix returned will have the type of whatever a T added to a K would be.
You won't be able to make custom rules with this but it will follow the standard promotion/conversion rules.
Variant of the method 3 from MathanOliver: define operator+() (off topic suggestion: ever define operator+=() as method and operator+() as external function) not as method but as external function (you can make it friend to Matrix if needed).
template <typename T1, typename T2,
typename Tr = decltype(std::declval<T1>() + std::declval<T2>())>
Matrix<Tr> operator+ (Matrix<T1> const & m1, Matrix<T2> const & m2)
{
// something useful
return {m1.width(), m1.height()};
}
The following is a full compiling example
#include <cstring>
#include <utility>
template <typename T>
class Matrix
{
public:
Matrix(unsigned int width, unsigned int height)
: width_(width), height_(height)
{ data_ptr_ = new T[width * height]; }
Matrix(const Matrix<T> & other)
: Matrix(other.width(), other.height() )
{ std::memcpy(data_ptr_, other.data(), width_ * height_ * sizeof(T)); }
virtual ~Matrix()
{ delete []data_ptr_; }
unsigned int width() const
{ return width_; }
unsigned int height() const
{ return height_; };
T * data() const
{ return data_ptr_; };
private:
T * data_ptr_;
unsigned int width_;
unsigned int height_;
};
template <typename T1, typename T2,
typename Tr = decltype(std::declval<T1>() + std::declval<T2>())>
Matrix<Tr> operator+ (Matrix<T1> const & m1, Matrix<T2> const & m2)
{
return {m1.width(), m1.height()};
}
int main ()
{
Matrix<int> m1{1, 2};
Matrix<float> m2{1, 2};
auto m3 = m1 + m2;
auto m4 = m2 + m1;
static_assert( std::is_same<decltype(m3), Matrix<float>>{}, "!" );
static_assert( std::is_same<decltype(m4), Matrix<float>>{}, "!" );
return 0;
}
Obtaining the type of the returned matrix as default template value (Tr) you can explicit a different type, if you want, as follows
auto m5 = operator+<int, float, int>(m1, m2);
static_assert( std::is_same<decltype(m5), Matrix<int>>{}, "!" );

Multi-overloading of operator* in template matrix class

I have a template class of myMatrix mainly like:
template<class T, int row, int col>
class myMatrix{
T *_mat;
public:
template<int r, int c> using matrix_t = T[r][c];
myMatrix(const matrix_t<row, col> &);
myMatrix(const myMatrix<T, row, col> &);
myMatrix &operator=( const myMatrix<T, row, col>& );
//...
// next is the part of * overloading
myMatrix<T, row, col> operator*(const T& scalar);
typename< int c2 >
myMatrix<T, row, c2> operator*( const myMatrix<T, col, c2>& );
typename< int c2 >
myMatrix<T, row, c2> operator*( const matrix_t<col, c2>& );
typename< int r2 >
friend myMatrix<T, r2, col> operator*( const matrix_t<r2, row>&, const myMatrix<T, row, col>& );
// ...
};
Then I design another class Reference:
template<int dim, int loop>
class Reference{
myMatrix<int, dim, loop> _matA;
myMatrix<int, dim, 1> _matC;
public:
Reference(const myMatrix<int, dim, loop> &, const Matrix<int, dim, 1> &);
Reference(const Reference<dim, loop> &);
Reference<dim, loop> &operator=(const Reference<dim, loop> &);
// ...
friend Reference<1, loop> operator*(const Matrix<int, 1, dim> &alpha,
const Reference<dim, loop> & ref)
{
return Reference(alpha * ref._matA, alpha * ref._matC); // **Problem!!!**
}
// ...
};
When I test the codes with something like
const int matA[3][3] = {1,2,3,4,5,6,7};
const int matC[3][1] = {1,2,3};
const int alp[][3] = {1,2,2};
Reference<3,3> ref(matA, matC);
Matrix<int, 1, 3> alpha(alp);
// Reference<1,3> ref_t = alp * ref;
Reference<1,3> ref_t = alpha * ref; // **can not compile!!!**
The problem occurs:
binary '*': no operator found which takes a left-hand operand of type 'const myMatrix' ( or there is no acceptable conversion )...
Then here come my questions:
Of all the +4 overloadings in class myMatrix, if there are any redundancies?
Maybe just the overloading version of typename< int c2 > myMatrix<T, row, c2> operator*( const myMatrix<T, col, c2>& ); can service the following two overloads since a built-in 2d-array like arr[][] can convert to a myMatrix due to my constructor myMatrix(const matrix_t<row, col> &);?
What is the reason for the compiling error?
The compiler error says what you've done wrong:
binary '*': no operator found which takes a left-hand operand of type 'const myMatrix'
You have
operator*(const myMatrix&);
but no
operator*(const myMatrix&) const;
So alpha * ref can't match (because alpha is const&).
The usual way to implement T::operator* is
T& operator*=(const T&);
T operator*(const T&) const;
Or (better), make the * operator a free function with two arguments (this can work better if you might need to promote the left-hand argument).

Misleading compiler error message: size_t is not a member of std?

I have the following header file containing a template class:
#ifndef VECTOR_H
#define VECTOR_H
namespace lgl
{
namespace maths
{
template<class T, std::size_t SIZE>
class Vector
{
public:
Vector();
Vector(T defaultValue);
Vector(const Vector<T, SIZE>& other);
Vector<T, SIZE>& operator=(const Vector<T, SIZE>& other);
~Vector();
//accessors
const std::size_t size() const;
const T& operator[](std::size_t i) const;
T& operator[](std::size_t i);
//vector operations
Vector<T, SIZE> operator+(const Vector<T, SIZE>& other) const;
Vector<T, SIZE> operator-(const Vector<T, SIZE>& other) const;
Vector<T, SIZE> operator*(const T& scalar) const ;
Vector<T, SIZE> operator/(const T& scalar) const ;
T operator*(const Vector<T, SIZE>& other) const;
void operator+=(const Vector<T, SIZE>& other);
void operator-=(const Vector<T, SIZE>& other);
void operator*=(const T& scalar);
void operator/=(const T& scalar);
bool operator==(const Vector<T, SIZE>& other) const;
bool operator!=(const Vector<T, SIZE>& other) const;
private:
T m_elements[SIZE];
};
template<class T, std::size_t SIZE>
std::ostream& operator<<(std::ostream& os, const Vector<T, SIZE>& vec);
template<class T>
Vector<T, 3> cross(const Vector<T, 3>& a, const Vector<T, 3>& b);
#include "Vector.tpp"
//typedefs
typedef Vector<float, 2> vec2f;
typedef Vector<float, 3> vec3f;
typedef Vector<float, 4> vec4f;
typedef Vector<double, 2> vec2d;
typedef Vector<double, 3> vec3d;
typedef Vector<double, 4> vec4d;
typedef Vector<int, 2> vec2i;
typedef Vector<int, 3> vec3i;
typedef Vector<int, 4> vec4i;
//factories
vec2f getVec2f(float x, float y);
vec3f getVec3f(float x, float y, float z);
vec4f getVec4f(float x, float y, float z, float h);
}
}
#endif
The .tpp file has all the implementations of the methods of the Vector template class. I also have a Vector.cpp file, which defines the factory functions, like this:
#include "Vector.h"
namespace lgl
{
namespace maths
{
//factories
vec2f getVec2f(float x, float y)
{
vec2f result;
result[0] = x;
result[1] = y;
return result;
}
vec3f getVec3f(float x, float y, float z)
{
vec3f result;
result[0] = x;
result[1] = y;
result[2] = z;
return result;
}
vec4f getVec4f(float x, float y, float z, float h)
{
vec4f result;
result[0] = x;
result[1] = y;
result[2] = z;
result[3] = h;
return result;
}
}
}
I get the errors: size_t is not a member of std, and ostream is not a member of std.
If I delete everything in the .cpp file and don't use the factories, everything's fine. So what could be the problem?
Write
#ifndef VECTOR_H
#define VECTOR_H
#include <iosfwd>
#include <cstddef>
namespace lgl
{
//...

Redefining Friend Function of Base Class in Derived Class

I want to redefine the operator* function that is originally defined as a friend in the Vector class, in a derived class, BigNum. Specifically I want to call the Vector version of operator* and then do some other things to the result of that operation in BigNum's operator*. Here's a snippet of the structure (thanks again to #lemmes for helping with this):
template<typename T>
class Vector
{
private:
std::vector<T> base;
public:
Vector();
Vector(const std::vector<T> vec);
Vector(const Vector& vec);
template<typename T1, typename T2>
friend auto operator*(const Vector<T1>& lhs, const Vector<T2>& rhs) -> Vector<decltype(std::declval<T1>() * std::declval<T2>())>;
};
template<typename T1, typename T2>
auto operator*(const Vector<T1>& lhs, const Vector<T2>& rhs) -> Vector<decltype(std::declval<T1>() * std::declval<T2>())>
{
typedef decltype(std::declval<T1>() * std::declval<T2>()) T3;
assert(lhs.base.size() == rhs.base.size());
Vector<T3> result;
result.base.reserve(lhs.base.size());
std::transform(lhs.base.begin(), lhs.base.end(), rhs.base.begin(), std::back_inserter(result.base),
[](const T1& e1, const T2& e2) { return e1 * e2; });
return result;
}
class BigNum : public Vector<int>
{
public:
BigNum();
BigNum(const std::vector<int> init);
~BigNum();
BigNum operator*(const BigNum& rhs);
};
#endif
BigNum BigNum::operator*(const BigNum& rhs)
{
// How can I call Vector's operator* (a friend of the Vector class)
// and then do other stuff in here?
}
#include "BigNum.h"
int main()
{
int arr1[] = {1,2,3,4,5};
int arr2[] = {10,20,30,40,50};
std::vector<int> vec1 (arr1, arr1 + sizeof(arr1) / sizeof(arr1[0]));
std::vector<int> vec2 (arr2, arr2 + sizeof(arr2) / sizeof(arr2[0]));
BigNum bn1(vec1), bn2(vec2);
bn1 * bn2; // want to call BigNum's operator* here
return 0;
}
I obviously can't do something like Vector::operator* since it's a friend. Thanks in advance!
You can write static_cast<Vector<int>&>(bn1) * static_cast<Vector<int>&>(bn2) to have the vector's overloaded operator called.