Here is a snippet of the code that I found on my beginner file:
struct TriIndex //triangle index?
{
int vertex; //vertex
int normal; //normal vecotr
int tcoord; //
bool operator<( const TriIndex& rhs ) const {
if ( vertex == rhs.vertex ) {
if ( normal == rhs.normal ) {
return tcoord < rhs.tcoord;
} else {
return normal < rhs.normal;
}
} else {
return vertex < rhs.vertex;
}
}
};
I've never seen a bool operator inside a struct before. Can anyone explain this to me?
TL;DR: The code inside the function is evaluating if *this is < rhs, bool is merely the return type.
The operator is operator < which is the less than operator. The current object is considered the left hand side or lhs, and the object compared against, the right hand of the a < b expression is rhs.
bool // return type
operator < // the operator
(const TriIndex& rhs) // the parameter
{
...
}
It returns true if the current object is less than (should preceed in containers, etc) the object after the < in an expression like:
if (a < b)
which expands to
if ( a.operator<(b) )
There is a bool operator:
operator bool () const { ... }
which is expected to determine whether the object should evaluate as true:
struct MaybeEven {
int _i;
MaybeEven(int i_) : _i(i_) {}
operator bool () const { return (_i & 1) == 0; }
};
int main() {
MaybeEven first(3), second(4);
if (first) // if ( first.operator bool() )
std::cout << "first is even\n";
if (second) // if ( second.operator bool() )
std::cout << "second is even\n";
}
bool operator<( const TriIndex& rhs )
This line of code is defining a comparison of user-defined datatypes. Here bool is the type of the value this definition will return i.e. true or false.
const TriIndex& rhs
This code is telling the compiler to use struct object as a parameter.
if ( vertex == rhs.vertex ) {
if ( normal == rhs.normal ) {
return tcoord < rhs.tcoord;
} else {
return normal < rhs.normal;
}
} else {
return vertex < rhs.vertex;
}
The above code is defining criteria of the comparison i.e. how the compiler should compare the two when you say struct a < struct b . This is also called Comparison Operator Overloading.
TL-DR;
So after defining the operator when you write a code say:
if (a < b) {
.......
}
where a and b are of type struct fam. Then the compiler will do the if else operations inside the definition and use the return value . If return = true then (a < b) is true otherwise the condition will be false.
That code allows you to compare different TriIndexes with the < operator:
TriIndex alpha;
TriIndex beta;
if (alpha < beta) {
etc;
}
bool operator<( const TriIndex& rhs ) is the "less than" operating (<), bool is the return type of the "less than" operator.
C++ allows you to override operators such as < for structs and classes. For example:
struct MyStruct a, b;
// assign some values to members of a and b
if(a < b) {
// Do something
}
What does this code do? Well it depends on how the "less than" operator has been defined for MyStruct. Basically, when you do a < b it will call the "less than" operator for that struct with b being rhs (right hand side) or whatever you call the first parameter, although rhs is the typical convention.
Related
In the code, why is (10 != i) calling == instead of !=? The other two call !=
#include <iostream>
class Integer
{
int x;
public:
bool
operator== (const Integer &i)
{
std::cout << "==";
return x == i.x;
}
bool
operator!= (const Integer &i)
{
std::cout << "!=";
return x != i.x;
}
Integer (int t = 0) { x = t; }
};
int
main ()
{
Integer i;
std::cout << (i != i) << '\n'; // calls !=
std::cout << (i != 100) << '\n'; // calls !=
std::cout << (10 != i) << '\n'; // calls ==
}
Prior to C++20, you'd need to add two free functions for the comparison where the int is on the left-hand side:
bool operator==(int lhs, const Integer& rhs) {
return rhs == lhs;
}
bool operator!=(int lhs, const Integer& rhs) {
return rhs != lhs;
}
You should also make the member comparison operators const qualified:
class Integer {
public:
//...
bool operator==(const Integer &i) const { // note const
std::cout << "==";
return x == i.x;
}
bool operator!=(const Integer &i) const { // note const
std::cout << "!=";
return x != i.x;
}
//...
};
You could also remove the member operators to simplify things. Now the left-hand side int will be implicitly converted to Integer and then compared with the right-hand side:
class Integer {
int x;
public:
Integer(int t = 0) : x{t} {}
friend bool operator==(const Integer& lhs, const Integer& rhs) {
return rhs.x == lhs.x;
}
friend bool operator!=(const Integer& lhs, const Integer& rhs) {
return !(rhs == lhs);
}
};
Since you've tagged this C++20, you can let operator== do all the work. See Default comparisons. It'll be used for operator!= too.
class Integer {
int x;
public:
bool operator==(const Integer &i) const {
std::cout << "==";
return x == i.x;
}
Integer(int t = 0) : x{t} {}
};
... and it'll correctly show that it used operator== for all your != comparisons (and negated it).
More from Defaulted equality comparison:
A class can define operator== as defaulted, with a return value of bool. This will generate an equality comparison of each base class and member subobject, in their declaration order. Two objects are equal if the values of their base classes and members are equal. The test will short-circuit if an inequality is found in members or base classes earlier in declaration order.
Per the rules for operator==, this will also allow inequality testing
This means that you will in fact get away with the below only since C++20:
class Integer {
int x;
public:
bool operator==(const Integer &i) const = default;
Integer(int t = 0) : x{t} {}
};
or even better, get all the comparison operators for free by defaulting the spaceship operator <=>:
class Integer {
int x;
public:
auto operator<=>(const Integer &i) const = default;
Integer(int t = 0) : x{t} {}
};
There are two new additions to C++20 that made this possible (note that your code doesn't compile in earlier standard versions).
Compiler will attempt to replace a != b with !(a == b) if there is no suitable != for these arguments.
If there is no suitable a == b, compiler will attempt b == a as well.
So, what happens - compiler first notices that it doesn't know how to compare 10 != i, so it tries !(10 == i). There is still no suitable comparison, so it tries !(i == 10) and it can finally be done using your implicit constructor to convert 10 to Integer.
It can be easily verified by adding more info to debug print:
bool
operator== (const Integer &i) const
{
std::cout << x << "==" << i.x << ' ';
return x == i.x;
}
will print 0==10 1 in the last line (see it online).
As noticed in comments, you don't even need operator !=, due to aforementioned behaviour C++20 compiler will automatically convert any such call to operator ==.
Currently, to compare 3 or more integers, We do it this way. (a < b) && (b < c). I know that, a < b < c translates to (a < b) < c and compares boolean with integer. Is there any way such that, I can overload some operators on a custom Class to achieve continuous comparison? How does languages like python does this?
Update: According to accepted answer, I managed to write a piece of code. Have a look.
#include <iostream>
template <typename T>
class Comparator {
bool result;
T last;
public:
Comparator(bool _result, T _last) : result(_result), last(_last) {}
operator bool() const {
return result;
}
Comparator operator<(const T &rhs) const {
return Comparator(result && (last < rhs), rhs);
}
Comparator operator>(const T &rhs) const {
return Comparator(result && (last > rhs), rhs);
}
};
class Int {
int val;
public:
Int(int _val) : val(_val) {}
operator int() const {
return val;
}
Comparator<Int> operator<(const Int &rhs) {
return Comparator<Int>(val < int(rhs), rhs);
}
Comparator<Int> operator>(const Int &rhs) {
return Comparator<Int>(val > int(rhs), rhs);
}
};
int main() {
Int a(2), b(3), c(1), d(4), e(6), f(5);
std::cout << (a < b > c < d < e) << '\n';
// 2 < 3 > 1 < 4 < 6 > 5
return 0;
}
a < b < c is grouped as (a < b) < c.
If a or b are a type that you define, you could overload < for that type to return a proxy object, for which an overloaded < is also defined. That proxy object would contain the value of b along with the result of a < b.
It's some hassle, and will not make your code readable either since all C++ programmers know what a < b < c should do.
Python has its own syntax and interpreter.
i searched a lot here and on other sites as well but i have not found something satisfying.
what i need is quite simple task - substantially to construct ORDER BY operator in c++. this means i have struct with a number of various data type members and i need a comparator for it with members and orderings configurable. here is my pseudocode idea:
comparator.add(&MyStruct::member1, std::less);
comparator.add(&MyStruct::member2, std::greater);
std::sort(my_vector.begin(), my_vector.end(), comparator);
and i get data sorted by member1 and if it is equal member2 decides, and so on.
i am not too good in stl and templates, but i can read and decipher some code and found this as very appropriate solution: https://stackoverflow.com/a/11167563
unfortunately in my work i have to use c++ builder with faulty 32bit compiler that refuses to compile this correct code. it does support almost nothing from c++11, it has boost 1.39 available.
does someone have any solution that could work for me with my resources available? thank you in advance
EDIT:
i got very specialised solutions with hard-written comparison operators which i am aware of and which do not work here too good. i missed this in my question. my struct has at least 15 members and as i wrote, i need to often change individual sort directions for members/columns (asc, desc). too, i need to often change set of sorted members, just like in order by operator in sql, for example. also i cannot use something like stable_sort as i am just writing comparator for something like OnCompare event of some class.
It's not too difficult. First, consider the "canonical"
ordering relationship:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
return lhs.a < rhs.a
|| ( !(rhs.a < lhs.a) && lsh.b < rhs.b )
|| ( !(rhs.a < lhs.a) && !(rhs.b < lhs.b) && lhs.c < rhs .c )
|| ...
}
};
Obviously, no one would actually write something like this, but
it corresponds exactly to the formal definition of what is
needed.
Of course, if we can imagine the data members as an array, we
could rewrite this as a loop, taking advantage of the previously
established !(rhs[i-1] < lsh[i-1] in each case:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
int i = 0;
while ( i != N && !(lhs[i] < rhs[i]) && !(rhs[i] < lhs[i]) ) {
++ i;
}
return i != N && lhs[i] < rhs[i];
}
};
Or, if all of the elements are fully ordered, so that == is
also defined on them, and we can assume that it corresponds to
the equivalence relationship established by the weak partial
ordering:
struct Compare
{
bool operator()( C const& lhs, C const& rhs ) const
{
int i = 0;
while ( i != N && !(lhs[i] == rhs[i]) ) {
++ i;
}
return i != N && lhs[i] < rhs[i];
}
};
All that remains is to somehow translate this into something
that can process an arbitrary ordering of elements of arbitrary
types. There's an old saying that the solution to every problem
is an additional level of indirection, and it applies here.
First, we need some means of handling the different types of
each element. Polymorphism seems appropriate (although
templates could be made to work if the order in which the
elements were evaluated were fixed at compile time):
struct CompareOneElementOfC
{
virtual bool isLessThan( C const& lhs, C const& rhs) const = 0;
virtual bool isEqual( C const& lhs, C const& rhs) const = 0;
};
template <typename T, T C::*ptr>
struct ConcreteCompareOneElementOfC : public CompareOneElementOfC
{
virtual bool isLessThan( C const& lhs, C const& rhs) const
{
return lhs.*ptr < rhs.*ptr;
}
virtual bool isEqual( C const& lhs, C const& rhs) const
{
return lhs.*ptr == rhs.*ptr;
}
};
Depending on the types of the elements, you may need to hand
write specific concrete instances. And if any of the elements
doesn't support total ordering, you will have to omit the
isEqual, and modify the following code accordingly.
Having got this far, we need exactly one static instance of each
concrete Compare:
ConcreteCompareOneElementOfC<int, &C::a> const c1;
ConcreteCompareOneElementOfC<double, &C::b> const c2;
// ...
Finally, put the addresses of these instances in a table:
CompareOneElementOfC const* const cmp[] = { &c1, &c2 ... };
You can have different tables for different orderings. If there
are only a few, define static tables for each, and be done with
it. If the orderings can be arbitrary, create the table on the
fly before each sort, in the desired order.
Finally:
class Compare
{
CompareOneElementOfC const* const* begin;
CompareOneElementOfC const* const* end;
public:
template< size_t N >
Compare( CompareOneElementOfC const* const (&cmp)[N] )
: begin( cmp )
, end( cmp + N )
{
}
bool
operator()( C const& lhs, C const& rhs ) const
{
auto current = begin;
while ( current != end && (*current)->isEqual( lhs, rhs ) ) {
++ current;
}
return current != end && (*current)->isLessThan( lhs, rhs );
}
}
(Please note that I haven't actually tested this code, so there
are probably typos and other errors. Still, the basic idea
should be there.)
I think just overloading operator < will work for you.
struct Struct {
int member1;
int member2;
bool operator<(const Struct& rhs) const {
if (member1 != rhs.member1)
return member1 < rhs.member1
else
return member2 > rhs.member2
}
};
This way whenever any 2 instances of Struct are compared, they will be compared by the comparison function defined in operator <.
So a simple std::sort(vec.begin(), vec.end()) will just work!
EDIT:
Otherwise you can always define a functor which can be used to compare each element. This is just a class with an overloaded operator () which is used for comparison.
class ComparisonClass {
public:
bool operator()(const Struct& lhs, const Struct& rhs) {
if (lhs.member1 != rhs.member1)
return lhs.member1 < rhs.member1
else
return lhs.member2 > rhs.member2
}
};
You can additionally define some member values of the ComparisonClass which define the order of comparisons.
Using it would be calling it like so std::sort(vec.begin(), vec.end(), ComparisonClass());
EDIT2:
Slightly more elaborate code -
class ComparisonClass {
public:
bool operator()(const Struct& lhs, const Struct& rhs) {
for(int i=0; i<m_comparisonOrder.size(); i++) {
int pos = m_comparisonOrder[i];
if (lhs[pos] != rhs[pos]) {
if (m_comparisonType[pos])
return lhs[pos] < rhs[pos];
else
return lhs[pos] > rhs[pos];
}
}
}
std::vector<int> m_comparisonOrder.
std::vector<bool> m_comparisonType;
};
Here I'm assuming that Struct has an operator [] which returns the appropriate member variable.
Why not have a specialized comparator function which first checks member1 and if equal then checks member2?
Like
bool comparator(const MyStruct& s1, const MyStruct& s2)
{
if (s1.member1 == s2.member1)
return s1.member2 > s2.member2;
else
return s1.member1 < s2.member1;
}
Hi I was wondering how I could tackle this problem,
I need to overload +, - and * operators but need to replace them with Logical operators for example;
"+" should use OR
0+0 = 0 , 0+1 = 1, 1+1 = 1 ,1+0 = 1
would i have to place in the overload some sort of if statment?
Any help on how i could do this?
Thanks
They will being using binary as the data type, two matrices with binary as their data
There's no need for an if statement, you just need to return the result of && and ||.
struct A
{
bool val;
bool operator + (const A& other) { return val || other.val; }
bool operator * (const A& other) { return val && other.val; }
};
Note that you can't overload operators for built-in types. At least one of the arguments must be user-defined.
You don't want to overload those operators for integers, or any other built-in types, do you? Because it's impossible. If you have your own class which contains a boolean or integer value then the logic goes something like this:
bool operator + (const MyClass& m1, const MyClass& m2)
{
return m1.GetMyBooleanMember() || m2.GetMyBooleanMember();
}
Overloading operator+(int, int) is not possible, however you can create a new type that wraps an int and has the behavior you want...
struct BoolInt
{
int i;
};
BoolInt operator+(BoolInt x, BoolInt y) { return { x.i || y.i }; }
BoolInt operator*(BoolInt x, BoolInt y) { return { x.i && y.i }; }
BoolInt operator-(BoolInt x, BoolInt y) { return { x.i || !y.i }; } // guessing
So suppose I have a class like this one:
class Point
{
private:
int x, y;
public:
void setX(int arg_x) { x = arg_x; }
void sety(int arg_y) { y = arg_y; }
int getX() const { return x; }
int gety() const { return y; }
};
Now I want to have a map like this one:
map<Point, Point> m;
But I need a third parameter. I read in cplusplus that this third parameter is to compare something, but I didn't understand what that something was. Can anyone explain that for me?
You can extend your class with such a method if you don't need a separate compare function
class Point
{
private:
int x, y;
public:
bool operator<( const Point& other) const
{
if ( x == other.x )
{
return y < other.y;
}
return x < other.x;
}
};
By default the stl map orders all elements in it by some notion of ordering. In this case this operator is used. Sometimes you dont have control over the Point class or you might want to use it in two different maps each defines its own ordering. For example one map might sort points by x first and other one might sort by y first. So it might be helpful if the comparison operator is independent of the class Point. You can do something like this.
class Point
{
public:
int x, y;
};
struct PointComparer
{
bool operator()( const Point& first , const Point& second) const
{
if ( first.x == second.x )
{
return first.y < second.y;
}
return first.x < second.x;
}
};
map<Point, Point , PointComparer> m;
What you need is to define an ordering of Point items.
This can be done in different ways :
Overload the operator < for Point
You can provide an overload of the < operator, whose prototype is :
bool operator < (const Point & p_lhs, const Point & p_rhs) ;
For example, for my tests, I used the following one :
bool operator < (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() < p_rhs.getX()) { return true ; }
if(p_lhs.getX() > p_rhs.getX()) { return false ; }
return (p_lhs.getY() < p_rhs.getY()) ;
}
This is the easiest way, but it assumes, semantically, that the ordering defined above is the right default one.
Providing a functor
If you are unwilling to provide a < operator, or want to have multiple maps, each one with its own ordering, your solution is to provide a functor to the map. This is the third template parameter defined for the map:
template < class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key,T> > > class map;
The functor must have the following signature :
struct MyCompareFunctor
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
// the code for comparison
}
} ;
So, for my tests, I just wrote the following :
struct MyCompare
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() > p_rhs.getX()) { return true ; }
if(p_lhs.getX() < p_rhs.getX()) { return false ; }
return (p_lhs.getY() > p_rhs.getY()) ;
}
} ;
And used it in my map:
std::map<Point, Point, MyCompare> map ;
Et voilĂ ...
Specializing std::less for Point
I see no point in doing this, but it's always good to know: You can specialize the std::less template structure for your Point class
#include <functional>
namespace std
{
template<>
struct less<Point> : binary_function <Point,Point,bool>
{
bool operator() (const Point & p_lhs, const Point & p_rhs)
{
if(p_lhs.getX() < p_rhs.getX()) { return true ; }
if(p_lhs.getX() > p_rhs.getX()) { return false ; }
return (p_lhs.getY() < p_rhs.getY()) ;
}
} ;
}
This has the same effect as overloading the operator <, at least, as far as the map is concerned.
As for the operator < solution above, semantically, this solution assumes that the ordering defined above is the right default one as far as std:less is concerned.
Note that the default std::less implementation calls the operator < of the is templated type. Having one giving different results than the other could be considered as a semantic error.
When you are using a user defined class as key in std::map, in order to determine the position of the elements in the container the map needs the Comparison class: A class that takes two arguments of the key type and returns a bool.
It is basically, a comparison functor/ function which compares two key values.
You don't need third parameter, you just need the operator== and operator<
bool operator<(const Point& other) const{
if ( x == other.x )
return y < other.y;
return x < other.x;
}
bool operator==(const Point& other) const{
return x == other.x && y == other.y;
}
I think the code above gives a little upgrade to #parapura rajkumar's solutions.
class Point{
private:
int x, y;
public:
bool operator<( const Point& other) const{
return ((x < other.x) || (y < other.y));
}
};
What you are saying as third parameter is called "Comparator" in STL.
For default types as keys youy don't need to provide one as compiler
does that job for you.
But for your-defined types you have to provide it OR else how would compiler maintain
the sort order in map/set etc.