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.