0
#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?

Resorter
  • 307
  • 3
  • 9
  • 1
    In this example, only `v3` needs to be be writeable. You can make `v1` and `v2` `const double*`. – François Moisan Oct 20 '16 at 18:33
  • You can copy a const value to a mutable variable and pass it to the function. – stark Oct 20 '16 at 18:35
  • @FrançoisMoisan Which function do you suggest me to make changes in? I assume I do not change testfn including the types of its parameters. – Resorter Oct 20 '16 at 18:38
  • @stark Is there a way so that I don't need to copy the CLS? Because potentially CLS can be a very large matrix. – Resorter Oct 20 '16 at 18:48
  • You aren't passing the matrix, you are trying to pass a const pointer to a function that expects a pointer. – stark Oct 20 '16 at 19:17

2 Answers2

1

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.

dwcanillas
  • 3,562
  • 2
  • 24
  • 33
  • Thanks for the detailed suggestion. Since testfn is essentially from a library. I don't know how I am supposed to change the pass-in parameters. – Resorter Oct 20 '16 at 19:14
  • I added a follow up question. Do you mind take a look at that one as well? – Resorter Oct 20 '16 at 19:29
  • @Resorter your code with the added `* operator` compiled fine for me. What compiler are you using? – dwcanillas Oct 20 '16 at 20:09
  • I use gcc to compile. – Resorter Oct 20 '16 at 22:06
  • @Resorter it looks like it is complaining about passing temporary variables as references. See this: http://stackoverflow.com/questions/27463785/cant-pass-temporary-object-as-reference Breaking each operation onto its own line and binding it to a named variable worked for me. – dwcanillas Oct 21 '16 at 18:13
0

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);
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Do you mind taking a look at the second question as well? – Resorter Oct 20 '16 at 22:19
  • @Resorter: that should have been posted as a separate question (regardless of how long SO makes you wait to post it). One question per post please. And when you do post a new question, please include the actual errors you are getting with the code in question. But I can already tell you that your operator input parameters are wrong. You are passing **non-const** references. They need to be **const** references, like in the original code. – Remy Lebeau Oct 20 '16 at 23:27