Home > Enterprise >  compiler gives invalid operands to binary expression error even if there is an overloaded stream ins
compiler gives invalid operands to binary expression error even if there is an overloaded stream ins

Time:02-25

@paddy 's answer solved the problem. I have to change non-const Coefficient argument with const Coefficient argument.

ostream & operator<< (ostream & output, const Coefficient & holder)

But why does const keyword fix the problem?

I'm trying to learn operator overloading and I get a below error

error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'Coefficient')
cout << (c   4) << endl ;

I mentioned the line that causes the compiler to give an error. (last line in the main)

#include <iostream>
#include <ostream>

using namespace std ;

class Coefficient {
    private:
        double myValue ;
        mutable int myAccesses ;

    public:
        Coefficient (double initVal) {
            myValue = initVal ;
            myAccesses = 0 ;
        }

        double GetValue (void) const {
            myAccesses   ;
            return myValue ;
        }

        bool operator= (double v) {
            myAccesses   ;
            if (v < 0 || v > 1) {
                return false ;
            }
            myValue = v ;
            return true ;
        }

        bool operator = (double addval) {
            return addValue(addval) ;
        }

        bool operator-= (double subval) {
            return addValue(-subval) ;
        }

        bool operator= (char * str) {
            if(!strcmp(str, "default")) {
                return operator=(0.5) ;
            } else if (!strcmp(str, "max")) {
                return operator=(0.0) ;
            } else if (!strcmp(str, "min")) {
                return operator=(1.0) ;
            } else {
                return false ;
            }
        }

        Coefficient operator  (double d) {
            Coefficient sum{ this->myValue   d} ;
            return sum ;
        }
    private:
        bool addValue (double v) {
            myAccesses   ;
            if (myValue   v < 0 || myValue   v> 1) {
                return false ;
            }
            myValue  = v ;
            return true ;
        }
} ;

Coefficient operator  (double leftval, Coefficient rightval) {
    return rightval   leftval ;
}

ostream & operator<< (ostream & output, Coefficient & holder) {
    output << (holder.GetValue()) ;
    return output ;
}

int main (void) {
     Coefficient c{0.5} ;
     cout << c << "\t";

     c = 0.75 ;
     cout << c << endl ;

     c = const_cast<char *>("max") ;
     cout << c << endl ;

     c = const_cast<char *>("default") ;
     cout << c << endl ;

     c = (c   4) ;
     cout << c << endl ;

     cout << (c   4) << endl ; // compiler gives error because of this line
}

I do overload the stream insertion operator and addition operator, and when I delete the last line, I can use my custom class with stream insertion operator and it prints a value.

As you can see at the end of the main, when I assigned the result of the summation to the variable, and then use the variable with stream insertion operator, I could print the value. But when I tried to use summation without assigning the variable, it gives an error.

Why does the compiler give that error? Why the compiler does not find proper overloaded function without assigning to the variable?

I am using mac os big sur. I use clang version 13.0.0

CodePudding user response:

The definition of your stream output operator accepts a reference to a Coefficient:

ostream & operator<< (ostream & output, Coefficient & holder) {
    output << holder.GetValue();
    return output;
}

This works in the naive case, when you have some variable of type Coefficient and you output it.

cout << c;   //<-- c is an lvalue

But there's a subtle thing going on here. The reference is what's called an lvalue -- that is, something that can be modified. The reason why this works is because you're allowed to modify c because it's non-const and exists in the stack in your main function.

Now, consider the problem call:

cout << (c   4);   //<-- (c   4) is an rvalue

The way c 4 was created was via a value returned from your operator overload. The return value is a temporary, because it's not actually being stored in a variable anywhere. Instead, it's created as a temporary that is used as an operand. The temporary is what's called an rvalue. The C standard prevents a program from holding non-const references to rvalues (a slight exception to this being rvalue references, which you are not using here and are not appropriate for this problem).

And so, the compiler error here is an overload resolution issue. You made a temporary value with c 4 but there is no function that can take it as an argument, nor is there any way to automatically convert it to match any other operator overload.

To correct the issue, you need to either copy it (make the parameter a non-reference), or pass it as a const reference. Usually, the latter is preferable:

ostream & operator<< (ostream & output, const Coefficient & holder) {
    output << holder.GetValue();
    return output;
}

This will fix the overload resolution problem, and since you have already correctly declared .GetValue() as const there should be no other issues. But, if you had not made that GetValue function const, you would get an error.

Basic rules of thumb for const-correctness:

  • if a function will not modify a parameter passed as a reference, make the reference const.
  • if a member function will not modify the object, make the function const.

CodePudding user response:

(c 4) is an rvalue (in type Coefficient&&) and it cannot be captured by Coefficient&).

Try to add another overload function like:

ostream & operator<< (ostream & output, Coefficient && holder);
  •  Tags:  
  • c
  • Related