Lambda expression for operator overloading - c++

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.

Related

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

Operator overloading for primitive types in C++

In C++, if you've got a class Foo, and you want users of Foo to be able to write:
Foo x;
x += 3;
, you can simply make a member function of Foo, Foo& operator+=(int rhs). If you want to be able to write:
Foo x;
int y = 3;
y += x;
, you cannot accomplish this by writing a member function of Foo, instead one has to write an external function, which usually must be declared as a friend of Foo.
How hard would it be for a future version of C++ to say that this can be written with a Foo member function int& operator+=(int &lhs, Reversed), where Reversed was some empty class whose sole purpose was to distinguish the two versions of the operator?
If this were done, it could probably eliminate the vast majority of the uses of the friend keyword in new code.
You can in fact define such an operator, because you are free to overload += for built-in types:
int& operator+=(int &lhs, Foo &rhs) {
lhs += rhs.somefield;
return lhs;
}
On the other hand, instead of writing overloaded functions for all possible operators, you can also provide a function that will allow implicit casts of class Foo to int:
class Foo {
... somefield;
operator int() {
return (int)somefield;
}
};

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>>.

C++ no match for operator*

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;

Overloading operator ++

Class declaration:
class unaryOperators
{
public:
int i;
unaryOperators (int tempI = 0)
{
i = tempI;
}
unaryOperators operator++ (int);
unaryOperators operator++ ();
};
Does this global definition correspond to postfix or prefix version of the overloaded operator++? Why?
unaryOperators operator++ (unaryOperators &one)
{
return one;
}
unaryOperators& operator++ (unaryOperators &one)
^^
is the non-member prefix unary increment operator.
The non-member postfix unary increment operator takes an additional int as an policy enforcing parameter.
unaryOperators operator++ (unaryOperators &one, int)
Reference:
C++03 Standard 13.5.7 Increment and decrement [over.inc]
The user-defined function called operator++ implements the prefix and postfix ++ operator. If this function is a member function with no parameters, or a non-member function with one parameter of class or enumeration type, it defines the prefix increment operator ++ for objects of that type. If the function is a member function with one parameter (which shall be of type int) or a non-member function with two parameters (the second of which shall be of type int), it defines the postfix increment operator ++ for objects of that type. When the postfix increment is called as a result of using the ++ operator, the int argument will have value zero.125)
[Example:
class X {
public:
X& operator++(); // prefix ++a
X operator++(int); // postfix a++
};
class Y { };
Y& operator++(Y&); // prefix ++b
Y operator++(Y&, int); // postfix b++
void f(X a, Y b) {
++a; // a.operator++();
a++; // a.operator++(0);
++b; // operator++(b);
b++; // operator++(b, 0);
a.operator++(); // explicit call: like ++a;
a.operator++(0); // explicit call: like a++;
operator++(b); //explicit call: like ++b;
operator++(b, 0); // explicit call: like b++;
}
—end example]
I think this will help you.
Every operator (that can be overloaded as a free function) takes one more argument when overloaded as a free function. The first argument corresponds to *this when overloaded as a member function.
bool AsMember::operator!() const;
bool operator!(const AsFreeFunction&);
bool AsMember::operator==(const AsMember& rhv) const;
bool operator==(const AsFreeFunction& lhv, const AsFreeFunction& rhv);
etc.
Increment operator is no exception to this.
Global overloaded operator++ functions expect the explicit specification of all the arguments, so if the overloaded operator ++ is postfix, we are supposed to add one default int argument (to distinguish postfix version from prefix) in addition to the prerequisite one (which determines the type on which the function needs to be applied).
unaryOperators operator++ (unaryOperators &one, int dummy)
{
return one;
}
In the case of prefix global overloaded operator++ functions, the only argument we need to specify is the prerequisite one (which determines the type on which the function needs to be applied).
unaryOperators operator++ (unaryOperators &one)
{
return one;
}
The free function is prefix as it lacks an int parameter.
Helpful guide for operator signatures.
The canonical version of preincrement is:
T &operator++(T &)
That is, return the operand by reference. Postincrement takes an unused int, so the global operator++ you defined is the preincrement operator.