Ran Wang - 5 months ago 18

C++ Question

I have some weird issues implementing the lazy assign and add as indicated in https://eigen.tuxfamily.org/dox/TopicInsideEigenExample.html.

The code is

`template<typename Derived> class Base;`

template<typename Derived, typename OtherDerived> class SumOp;

template<typename Derived, typename OtherDerived>

class SumOp: public Base<SumOp<Derived, OtherDerived>>{

public:

Derived & lhs;

OtherDerived & rhs;

SumOp(Derived & lhs_, OtherDerived & rhs_):lhs(lhs_), rhs(rhs_){}

double packet(size_t index, Base<OtherDerived>& src){

return lhs.packet(index)+ rhs.packet(index);

}

};

template<typename Derived, typename OtherDerived>

struct Assign{

static Derived& run(Derived & dst, OtherDerived & src){

size_t length = dst.size();

for (size_t index =0; index < length; index++){

dst.copyPacket(index, src);

}

return dst;

}

};

template<typename Derived>

class Base{

public:

Base(){}

Derived& derived(){

return *static_cast<Derived*>(this);

}

const Derived& derived() const{

return *static_cast<const Derived*>(this);

}

template<typename OtherDerived>

SumOp<Derived,OtherDerived> operator+(Base<OtherDerived> & other){

return SumOp<Derived, OtherDerived>(this->derived(), other.derived());

}

template<typename OtherDerived>

Derived & operator=(Base<OtherDerived>& other){

return Assign<Derived, OtherDerived>::run(derived(), other.derived());

}

template<typename OtherDerived>

void copyPacket(size_t index, Base<OtherDerived> & other){

derived().writePacket(index, other.derived().packet(index));

}

};

class Vector: public Base<Vector> {

public:

double * data;

size_t nRow;

Vector(size_t nRow_):nRow(nRow_){

data = (double *)malloc(sizeof(double)*nRow);

}

~Vector(){

free(data);

}

template<typename OtherDerived>

Vector& operator=( Base<OtherDerived>& other){

return Base<Vector>::operator=(other);

}

size_t size(){

return nRow;

}

void writePacket(size_t index, double src){

data[index] = src;

}

double packet(size_t index){

return data[index];

}

};

In short, the problem lies in when I call

`operator=`

`Base<SumOp<Vector, Vector>>`

`SumOp<Vector, Vector>&`

`operator+`

`SumOp<Vector, Vector>`

The compiler error is

`no known conversion for argument 1 from ‘SumOp<Vector, Vector>’ to ‘Base<SumOp<Vector, Vector> >&’`

I am not sure why the implementation in Eigen is OK and how to fix this issue.

Thanks for the help.

The problem occurs when I call the following functions

`void test_vector(){`

Vector a(10), b(10), c(10);

for (int i=0;i<10;i++){

a.data[i]=1.0;

b.data[i]=1.0;

}

//This is very it goes wrong

c = a+b;

for (int i =0 ; i<10;i++){

std::cout << c.data[i] << std::endl;

}

};

With g++-6 the error reads

`invalid initialization of non-const reference of type ‘Base<SumOp<Vector, Vector> >&’ from an rvalue of type ‘Base<SumOp<Vector, Vector> >’`

c = a+b;

~^~

In file included from /home/ran/Desktop/experiment/PointerMatrix/vector.cpp:6:0:

/home/ran/Desktop/experiment/PointerMatrix/vector.h:76:21: note: initializing argument 1 of ‘Vector& Vector::operator=(Base<OtherDerived>&) [with OtherDerived = SumOp<Vector, Vector>]’

Vector& operator=( Base<OtherDerived>& other){

Answer

The problem is because the arguments to your `operator`

functions aren't const references. `operator+`

returns a temporary `SumOp`

object, which cannot be passed as a non-const reference. (Some compilers may support this as an extension.)

Changing the parameters to be `const &`

types should fix this problem.