Resorter
Resorter

Reputation: 317

When overload an operator in C++, how to get around with invalid conversion from 'const double*' to 'double*'

#include <iostream>
#include <vector>
using namespace std;


void testfn(double* v1, double *v2, double *v3, int n);//I must use this function

class CLS{
private:
    vector<double> v;
public:
    CLS(vector<double> vin);
    CLS operator+(const CLS & A)const;
};

CLS::CLS(vector<double> vin)
{
    v=vin;
}

CLS CLS::operator+(const CLS &A)const{
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(),0);
    testfn(&*v.begin(),&*A.v.begin(),&*vtmp.begin(),(int)v.size());
    CLS C(vtmp);
    return C;
}

void testfn(double* v1, double *v2, double *v3, int n)
{
    for (int i=0;i<n;i++)
    {
        *v3=*v1+*v2;
        ++v1;
        ++v2;
        ++v3;
    }
}

int main(){
    vector<double> v1(100,1.0), v2(100,2.0);
    CLS C1(v1),C2(v2);
    CLS C3=C1+C2;
    return 0;
}

In the above sample code, I create a class CLS and an overloaded operator +. In the definition of +, I call a function whose parameters contain double* pointers. In my real code this function is replaced by a function in LAPACK so I can not change it. Therefore when I ask this question, I assume we do not change anything about testfn and the fact that we must use testfn to define operator +. But I got the following error messages. How can I get rid of them?

test1.cpp: In member function 'CLS CLS::operator+(const CLS&) const':
test1.cpp:25:66: error: invalid conversion from 'const double*' to 'double*' [-fpermissive]
     testfn(&*v.begin(),&*A.v.begin(),&*vtmp.begin(),(int)v.size());
                                                                  ^
test1.cpp:6:6: note:   initializing argument 1 of 'void testfn(double*, double*, double*, int)'
 void testfn(double* v1, double *v2, double *v3, int n);
      ^
test1.cpp:25:66: error: invalid conversion from 'const double*' to 'double*' [-fpermissive]
     testfn(&*v.begin(),&*A.v.begin(),&*vtmp.begin(),(int)v.size());
                                                                  ^
test1.cpp:6:6: note:   initializing argument 2 of 'void testfn(double*, double*, double*, int)'
 void testfn(double* v1, double *v2, double *v3, int n);
      ^
make: *** [test1.o] Error 1

A follow up question (I can not post two questions in 90 minutes so I just add it behind this one)

#include <iostream>
#include <vector>
using namespace std;

void testfn(double* v1, double *v2, double *v3, int n);//I must use this function

class CLS{
private:
    vector<double> v;
public:
    CLS(vector<double> vin);
    CLS operator+(CLS & A);
    CLS operator*(CLS & A);
};

CLS::CLS(vector<double> vin)
{
    v=vin;
}

CLS CLS::operator*(CLS &A){
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(),0);
    testfn(&*A.v.begin(),&*v.begin(),&*vtmp.begin(),(int)A.v.size());
    CLS C(vtmp);
    return C;
}

CLS CLS::operator+(CLS &A){
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(),0);
    testfn(&*A.v.begin(),&*v.begin(),&*vtmp.begin(),(int)A.v.size());
    CLS C(vtmp);
    return C;
}

void testfn(double* v1, double *v2, double *v3, int n)
{
    for (int i=0;i<n;i++)
    {
        *v3=*v1+*v2;
        ++v1;
        ++v2;
        ++v3;
    }
}

int main(){
    vector<double> v1(100,1.0), v2(100,2.0), v3(100,0.0);
    CLS C1(v1),C2(v2),C3(v3);
    CLS C4=C1*(C1+(C2*C3+C2))*C1;
    return 0;
}

I create class CLS and defined two operators + and *. I want to use these operators as simply as how we use + and * for integers and doubles. Therefore I have a test line in the main CLS C4=C1*(C1+(C2*C3+C2))*C1;. However I get tons of errors when compiling this code. I am not familiar enough with the rules of operator overloading. How should I modify the definition (maybe just parameters?) of * and + so that CLS C4=C1*(C1+(C2*C3+C2))*C1; is valid?

Upvotes: 0

Views: 279

Answers (2)

dwcanillas
dwcanillas

Reputation: 3651

Ideally, you would change the parameters of testfn to all be const. You have said in the comments that isn't an option. From your definitions here there isn't really a reason they can't be changed, but I'll ignore that for now.

If you need the +operator to remain const, you could create deep copies of v and A to pass in to test_fn.

CLS CLS::operator+(const CLS & A) const
{
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(), 0);
    vector<double> v1 = v;
    vector<double> v2 = A.v;
    testfn(&*v1.begin(), &*v2.begin(), &*vtmp.begin(), (int)v.size());
    CLS C(vtmp);

    return C;
}

If copies are expensive, and you are sure testfn doesn't modify the inputs, you can const_cast the inputs instead.

Another possibility would be to remove all the const qualifiers on the +operator:

CLS CLS::operator+(CLS & A)
{
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(), 0);
    testfn(&*v.begin(), &*A.v.begin(), &*vtmp.begin(), (int)v.size());
    CLS C(vtmp);
    return C;
}

because testfn takes pointers that aren't const, you don't really have any guarantee that it isn't changing the values inside of v or A.

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 596352

Ideally, you should redeclare testfn() to make its read-only parameters be const:

void testfn(const double* v1, const double *v2, double *v3, int n);

But, if that is not an option for you, you could at least have operator+ simply const_cast away the constness when using A.v:

CLS CLS::operator+(const CLS &A) const
{
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(), 0);

    // if the vectors are empty, the begin() iterators
    // will match the end() iterators, and dereferencing
    // an end() iterator is undefined behavior! So make
    // sure the vectors are not empty...
    if (!v.empty())
        testfn(&*v.begin(), &*const_cast<CLS&>(A).v.begin(), &*vtmp.begin(), (int)v.size());
    return CLS(vtmp);
}

BTW, using &*begin() is pretty ugly, you could use std::vector::operator[] instead:

CLS CLS::operator+(const CLS &A) const
{
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(), 0);

    // if the vectors are empty, accessing any elements
    // is undefined behavior! So make sure the vectors
    // are not empty...
    if (!v.empty())
        testfn(&v[0], &(const_cast<CLS&>(A).v[0]), &vtmp[0], (int)v.size());
    return CLS(vtmp);
}

Or, if you are using C++11 or later, use std::vector::data() instead:

CLS CLS::operator+(const CLS &A) const
{
    //assuming the two vectors have the same length
    vector<double> vtmp(v.size(), 0);

    // if the vectors are empty, accessing any elements
    // is undefined behavior! So make sure the vectors
    // are not empty...
    if (!v.empty())
        testfn(v.data(), const_cast<CLS&>(A).v.data(), vtmp.data(), (int)v.size());
    return CLS(vtmp);
}

Upvotes: 0

Related Questions