C++ no match for operator* - c++

I want to overload operator:
static Vector operator*(float s, Vector right){
Vector result(right.getX()*s, right.getY()*s, right.getZ()*s);
return result;
}
When I want to use it:
Vector a(0,1,5)
Vector v(4*a);
I got:
error: no match for 'operator*' (operand types are 'int' and 'Vector')
What is wrong?

You need to declare (within class declaration) operator* as non-static non-member and friend like:
friend Vector operator*(float s, Vector right);
and define as (outside class declaration):
Vector operator*(float s, Vector right){
return Vector(right.getX()*s, right.getY()*s, right.getZ()*s);
}
Operator * is used as binary operator here. If you make as member, then first argument is implicitly taken as the current object (on which * applies, for example, if you use x * y, then operator * applies on x for member). However, for non-member both the arguments can be non-Vector type and can be converted to Vector if needed.
This will even work if you make as non-member non-friend and as static (tobe defined outside class declaration)

According to the C++ Standard (13.5 Overloaded operators)
6 An operator function shall either be a non-static member function or
be a non-member function
Define the function outside the class as
Vector operator *( float s, const Vector &right )
{
Vector result( right.getX() * s, right.getY() * s, right.getZ() * s );
return result;
}
Take into account that member functions getX(), getY() and getZ() shall be defined with qualifier const. For example
float getX() const;

Related

Systematic approach of how to think about operator overloading

I'm learning how to do operator overloading and trying to come up with a systematic approach of how to know number of arguments an overloaded operator should take in and if the function should be constant.
I know the system is not perfect and doesn't catch all the edge cases, but I'm thinking that will work itself out with some logical thinking in the end.
What I'm looking for is if this systematic approach is catching the majority of cases, or am I missing something important?
Systematic approach
Important: Think logically through the entire process regarding if the input paramters can be const, * or &.
Is the operator overloader a member function and NOT a stream?* It should take 1 argument which is the value/object to the right of the operator, UNLESS it is a unary operator then it should take 0 arguments.
Does it alter the class object? If it does, add const to the end of it.
Is the operator overloader a member function and ALSO a stream?* It should take 2 arguments, first a reference to the stream object and secondly (most likely) a reference to the class object.
Does it alter the class object? If it does, add const to the end of it.
Is the operator overloader NOT a member function?* In that case it should take 2 arguments which is the value/object to the left and right of the operator, UNLESS it is a unary operator then it should take 1 argument. No const at the end needed.
Below is the header file that I based the system on.
Vector.h
#pragma once
#include <iostream>
class Vector
{
public:
Vector(double x = 0.0, double y = 0.0);
Vector& operator+=(Vector const& other);
Vector& operator-=(Vector const& other);
Vector& operator*=(double other);
Vector& operator/=(double other);
Vector operator-() const;
bool operator==(Vector const& other) const;
bool operator!=(Vector const& other) const;
double operator*(Vector const& rhs) const;
double length() const;
friend std::ostream& operator<<(std::ostream& os, Vector const& other);
friend std::istream& operator>>(std::istream& is, Vector& other);
private:
double x;
double y;
};
Vector operator+(Vector const& lhs, Vector const& rhs);
Vector operator-(Vector const& lhs, Vector const& rhs);
Vector operator*(Vector const& lhs, double rhs);
Vector operator*(double lhs, Vector const& rhs);
Vector operator/(Vector const& lhs, double rhs);
You got one thing wrong:
friend std::ostream& operator<<(std::ostream& os, Vector const& other);
You say this is written with two explicit arguments "because one of them is a stream." But actually it takes two explicit arguments because the friend keyword on the front implies this is a free function, not a member function. So it's covered by your third rule, and your second rule should be deleted entirely.
Its both less and more diverse than you sketched.
More diverse because your systematic approach misses some operators. operator() and, since C++23, operator[] can have arbitrary number of arguments. ++ and -- have an argument merely to distinguish between post and pre de/increment.
Less diverse, because your confusion seems to be mainly related to operators declared as friends defined inside the class definition. And friend / free function or member and number of arguments isn't really specific to operator overloading.
Whether a free function is a friend and defined in the class definition has some impact on ADL. Though, operators as friends are not much different than other free functions as friends. For example:
struct foo {
friend void do_something(foo) {}
};
struct bar {};
void do_something(bar) {}
int main() {
do_something(foo{});
do_something(bar{});
}
Two classes, foo and bar, and for both there is a free function called do_something. It is important to note that the do_something defined in foo is not a member of foo. I may look rather similar to a member function definition but it is none. ADL aside (which is the reason we can actually call do_something(foo{})), the only reason we would prefer making do_something a friend is when it needs access to private members. And thats the same for operator overloads.
Now consider the difference between a free function and a member function:
struct moo {
int x;
void print_x() const { std::cout << x; }
};
void print_x(const moo& m) { std::cout << m.x; }
They both do exactly the same thing. Both need an object to be called. One is called like this m.print_x(); the other is called like this print_x(m);.
Ergo, the number of parameters does not depend on whether it is a friend of the class. A member function needs one argument less than a free function that does the same.
For the rest I refer you to https://en.cppreference.com/w/cpp/language/operators. Most importantly it has a list that tells you (among other things) which operators can be overloaded as free function and which operators can only be overloaded as members. For those that can be free functions you need to decide: Free function or member. If you go for free function and it needs access to private members, you must make it a friend.
Overloads for std::ostreams << are somewhat special. Or actually not that special, you just need to consider that you are overloading an operator of std::ostream not one of your class. Because you cannot add a member to std::ostream such overloads can only be free functions.
Regarding const the usual applies. If it can be const, make it const.

Which takes precedence, the free function operator==() or the member function operator==()?

When the free operator function and the member operator function are both defined, which one is used for comparison?
#include <iostream>
class A;
class B;
bool operator==(const A &a, const B &b){ return true; };
class A
{
public:
bool operator==( const B &rhs ){ return false; };
};
class B
{
};
int main( int argc, char **argv )
{
A a;
B b;
if( a == b )
{
std::cout << "a==b" << std::endl;
}
};
I ran the code a couple times and it seems that the member operator wins out. Is this always the case?
I ran the code a couple times and it seems that the member operator wins out.
Yes, the member wins in your example. But not for the reason you think.
Member functions have an implicit object parameter (what this points to), and the type of the object parameter is determined by the cv-qualifiers at the end of the member function. In this case, your member operator has no cv-qualifiers, so the type of the implicit object is simply A.
Basically, we have two candidates:
bool operator==(A const&, B const&); // your non-member operator
bool operator==(A&, B const&); // your member operator
The member operator is a better match because the first parameter is a better match - we don't have to take a more const-qualified reference to a.
If you had made your operator const (as you generally should), then we'd have these two candidates:
bool operator==(A const&, B const&); // your non-member operator
bool operator==(A const&, B const&); // better member operator
Which are identical, there is no reason to prefer one to the other, and we'd get an ambiguity. There is no rule to prefer a member to a non-member function (or vice versa).
You're declaring the 1st parameter type as const & in the non-member operator. Then given a == b, for the non-member operator to be called a needs to be converted to const. On the other hand the member operator is declared as non-const, then its operand is a non-const A then it's an exact match and wins in overload resolution.
If you change the 1st parameter type of the non-member operator to A& you'll get an ambiguity error. LIVE
Or qualify the member operator as const you'll get the ambiguity error too. LIVE

Lambda expression for operator overloading

Is it possible to write lambda expression for overloading operators?
For example, I have the following structure:
struct X{
int value;
//(I can't modify this structure)
};
X needs == operator
int main()
{
X a = { 123 };
X b = { 123 };
//[define equality operator for X inside main function]
//if(a == b) {}
return 0;
}
== operator can be defined as bool operator==(const X& lhs, const X& rhs){...}, but this requires adding a separate function, and my comparison is valid only within a specific function.
auto compare = [](const X& lhs, const X& rhs){...} will solve the problem. I was wondering if I can write this lambda as an operator.
Is it possible to write lambda expression for overloading operators?
No.
Operator overload functions must be functions or function templates. They can be member functions, member function templates, non-member functions, or non-member function templates. However, they cannot be lambda expressions.
From the C++11 Standard/13.5 Overloaded operators, para 6:
An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.

How to declare operator/ overload function to operate on a const variable and a non-const variable?

I have the following code
#pragma once
#include "material.h"
#include "../Math/vector.h"
#include <cmath>
class LambertianMaterial : public Material
{
public:
LambertianMaterial(Vector rho);
Vector brdf(Vector wi) const
{
return mRho / M_PI; // Error here
}
private:
Vector mRho;
};
In the line corresponding to the return statement of brdf I am getting the following error
Invalid operands to binary expression ('const Vector' and 'double')
In the class vector I have declared the operator/ like
Vector operator/(const float a);
I was thinking of redefining the method to
friend Vector operator/(const Vector& v, const float& a);
Is this a good way of doing it or is there a way so that the current definition of the operator accounts for the const Vector case?
You could make it a const member function, which could be applied for const and non-const object, if it won't (and it shouldn't) modify any non-static member variables.
Vector operator/(const float a) const;
As you thought, making it non-member function (and declared as friend if necessary) could do the work too. IMO I prefer to it for operator/. See Operator overloading : member function vs. non-member function? for more informations.

My understanding of friend functions

Sometimes a non-member function may need access to the private members it's taking in as a agrument.
A friend function is a non-member function that gives private access to the classes it's friends with.
Class X{
int number;
public:
X& operator+=(const X& rhs);//a += b is a.operator(b)
friend int& operator+=(int& addthis, const X& rhs);//add this += b is I don't know what lol
}
X& operator+=(const X& rhs){
this->number = this->number + rhs.number;
}
int& operator+=(int& addthis, const X& rhs){
addthis = addthis + rhs.number;
return *this;
}
What I read is that if I wanted to do += to an object, object += int, just overload the += operator, but what if the int came before the object. Say int += object? Than I would have to write it as a friend function, and that's where I get a little lost. Why can't I just write int& operator+=(int& addthis, const X& hrs); as a member function? I assume a friend function can work with other classes since it's a non-member function, so it's not assigned to any specific class?
I'm sorry I just don't understand why I would use friend function over making it a member function. Really would appreciate any feedback, thank you.
You can enable the operator+= for int and other integral types via a user-defined conversion in your class X:
struct X{
int number;
operator int() const
{
return number;
}
//...
}
Of course, this doesn't give you exactly the same behaviour as your friend-approach, as other functions could also use the conversion. Nevertheless, I guess this is what you are looking for, as otherwise you would need to define as well operator-=, operator*= and so on.
As far as I understand, you can't have operator*, operator+ or operator+= or any of operator# where # is some math operator that returns something other than an instance of your class right in the definition of your class.
In real world, it would be quite odd to add an integer to an integer and get an apple as a result. The same should apply to classes in C++. A member function is, well, a property of the class, a function that represents whatever can be done to the object of this class. Operators are special. They represent operations that sort of can't be made easier (what will you use to code an addition operator using the + sign instead of operator overloading?). They represent the very basic operations and thus should return an instance of the class they're members of.
Consider you implemented operator overloading as member function and performed something like x += y where both x and y are objects of the class which has the operator += overloaded.
Compiler parses x += y as x.operator+=(y) which is fine as both operands x and y are of the same class which has the operator += overloaded.
Now consider an expression like 2 += y (this may be insane, but I am trying explain why operator overloading with friend functions may be at time beneficial over operator overloading with member functions)
Since, the expression 2 += y will be parsed by compiler as 2.operator+=(y), an error is raised. Maybe 2 may get converted to an object of the class using constructor for conversion; (Single argument constructors can be used for conversion) but that is not the point here.
Using friend function to overload the operator calls the above expression 2 += y as operator+=(2, y) which works fine.
The reason why the operator int += X has to be a free function is that the compiler only searches for applicable member operators in the lhs type, and not in the rhs type. Since int is not a type that can be extended, you can't define this operator as a member function.
You were almost there, just a few errors:
class X;
int operator+=(int addthis, const X& rhs);
class X{
int number;
public:
X& operator+=(const X& rhs);//a += b is a.operator(b)
friend int operator+=(int addthis, const X& rhs);//add this += b is I don't know what lol
};
X& X::operator+=(const X& rhs){
this->number = this->number + rhs.number;
return *this;
}
int operator+=(int addthis, const X& rhs){
addthis = addthis + rhs.number;
return addthis;
}
some forward declarations added
int passed by value instead of by reference
missing semicolon after class declaration
class instead of Class
return corrected
Note that X += int is a member function, while int += X is a free function, declared a friend of the class X.
Using a free function for int += X is the only solution that allows to use the operator as usual, like:
X x;
int i = 2;
i += x;
The friend modifier is just meant to expose private data. Normally, you wouldn't define a friend function as a non-member if it only depends on the private data of a class it can be defined as a member function for.
A better example would be ostream::operator<< or istream::operator>>.