Defining operator for a struct
This is quite an old question and as a consequence all answers here are obsolete. C++11 allows a more elegant and efficient solution:
bool operator <(const MyStruct& x, const MyStruct& y) {
return std::tie(x.a, x.b, x.c) < std::tie(y.a, y.b, y.c);
}
Why is this better than using boost::make_tuple
? Because make_tuple
will create copies of all the data members, which can be costly. std::tie
, by contrast, will just create a thin wrapper of references (which the compiler will probably optimise away entirely).
In fact, the above code should now be considered the idiomatic solution to implementing a lexicographical compare for structures with several data members.
Overloading operators in typedef structs (c++)
The breakdown of your declaration and its members is somewhat littered:
Remove the typedef
The typedef
is neither required, not desired for class/struct declarations in C++. Your members have no knowledge of the declaration of pos
as-written, which is core to your current compilation failure.
Change this:
typedef struct {....} pos;
To this:
struct pos { ... };
Remove extraneous inlines
You're both declaring and defining your member operators within the class definition itself. The inline
keyword is not needed so long as your implementations remain in their current location (the class definition)
Return references to *this
where appropriate
This is related to an abundance of copy-constructions within your implementation that should not be done without a strong reason for doing so. It is related to the expression ideology of the following:
a = b = c;
This assigns c
to b
, and the resulting value b
is then assigned to a
. This is not equivalent to the following code, contrary to what you may think:
a = c;
b = c;
Therefore, your assignment operator should be implemented as such:
pos& operator =(const pos& a)
{
x = a.x;
y = a.y;
return *this;
}
Even here, this is not needed. The default copy-assignment operator will do the above for you free of charge (and code! woot!)
Note: there are times where the above should be avoided in favor of the copy/swap idiom. Though not needed for this specific case, it may look like this:
pos& operator=(pos a) // by-value param invokes class copy-ctor
{
this->swap(a);
return *this;
}
Then a swap method is implemented:
void pos::swap(pos& obj)
{
// TODO: swap object guts with obj
}
You do this to utilize the class copy-ctor to make a copy, then utilize exception-safe swapping to perform the exchange. The result is the incoming copy departs (and destroys) your object's old guts, while your object assumes ownership of there's. Read more the copy/swap idiom here, along with the pros and cons therein.
Pass objects by const reference when appropriate
All of your input parameters to all of your members are currently making copies of whatever is being passed at invoke. While it may be trivial for code like this, it can be very expensive for larger object types. An exampleis given here:
Change this:
bool operator==(pos a) const{
if(a.x==x && a.y== y)return true;
else return false;
}
To this: (also simplified)
bool operator==(const pos& a) const
{
return (x == a.x && y == a.y);
}
No copies of anything are made, resulting in more efficient code.
Finally, in answering your question, what is the difference between a member function or operator declared as const
and one that is not?
A const
member declares that invoking that member will not modifying the underlying object (mutable declarations not withstanding). Only const
member functions can be invoked against const
objects, or const
references and pointers. For example, your operator +()
does not modify your local object and thus should be declared as const
. Your operator =()
clearly modifies the local object, and therefore the operator should not be const
.
Summary
struct pos
{
int x;
int y;
// default + parameterized constructor
pos(int x=0, int y=0)
: x(x), y(y)
{
}
// assignment operator modifies object, therefore non-const
pos& operator=(const pos& a)
{
x=a.x;
y=a.y;
return *this;
}
// addop. doesn't modify object. therefore const.
pos operator+(const pos& a) const
{
return pos(a.x+x, a.y+y);
}
// equality comparison. doesn't modify object. therefore const.
bool operator==(const pos& a) const
{
return (x == a.x && y == a.y);
}
};
EDIT OP wanted to see how an assignment operator chain works. The following demonstrates how this:
a = b = c;
Is equivalent to this:
b = c;
a = b;
And that this does not always equate to this:
a = c;
b = c;
Sample code:
#include <iostream>
#include <string>
using namespace std;
struct obj
{
std::string name;
int value;
obj(const std::string& name, int value)
: name(name), value(value)
{
}
obj& operator =(const obj& o)
{
cout << name << " = " << o.name << endl;
value = (o.value+1); // note: our value is one more than the rhs.
return *this;
}
};
int main(int argc, char *argv[])
{
obj a("a", 1), b("b", 2), c("c", 3);
a = b = c;
cout << "a.value = " << a.value << endl;
cout << "b.value = " << b.value << endl;
cout << "c.value = " << c.value << endl;
a = c;
b = c;
cout << "a.value = " << a.value << endl;
cout << "b.value = " << b.value << endl;
cout << "c.value = " << c.value << endl;
return 0;
}
Output
b = c
a = b
a.value = 5
b.value = 4
c.value = 3
a = c
b = c
a.value = 4
b.value = 4
c.value = 3
Where to declare a struct operator overloading
You’re mixing up declaration and definition in your code. Put the definitions into the implementation file (*.cpp
). Put the declarations into the header, next to your declaration of round
.
Alternatively, you could put the definitions into the header and declare them inline
(and this is routine for short functions such as custom operators). The inline
specifier on functions prevents functions from violating the One Definition Rule when included by multiple translation units.
operator== in C++ struct
When overloading an binary operator as a member function, the first parameter is this
pointer. In the signature you have defined the operator==
, it will take 3 arguments. However, it can only take two.
In you case I would recommend making it a non-member function.
typedef struct _tBScan {
QString strQuadpackNumbers;
uint uintBegin, uintEnd;
} tBScan;
bool operator==(const struct _tBScan& a, const struct _tBScan& b) {
return (a.strQuadpackNumbers.compare(b.strQuadpackNumbers) == 0 &&
a.uintBegin == b.uintBegin && a.uintEnd == b.uintEnd);
}
When you overload the, let's say, operator@
the expression _tBScan @ _smt
is resolved into.
_tBScan.operator@(_smt);
When it's not a member function the expression is resolved into
operator@(_tBScan, _smt);
So the compiler searches the overload of either of them.
How to properly overload operator in a struct to enable use in a set in C++
Did you look at the compile error?
As it says, the method needs to be const
bool operator<(const Coordinate& other) const { // const the < operator
return this->x * this->y < other.x * other.y;
}
How can I add operator definition to an existing struct from a header file?
You can simply use custom functor in your unordered_map
declaration.
Indeed, unordered_map
provides custom template arguments for this purpose.
Note: you need to provide a functor to compute the hash value too for unordered_map
.
template<
class Key,
class T,
class Hash = std::hash<Key>, // <----- You need hash for Key
class KeyEqual = std::equal_to<Key>, // <---- Equal Functor
// ...
Just define your functor in accordance with the logic of your program. Something like:
struct AsnObjectIdentifierHasher {
std::size_t operator()(const AsnObjectIdentifier&) const noexcept;
};
struct AsnObjectIdentifierComparator {
bool operator()(const AsnObjectIdentifier&,
const AsnObjectIdentifier&) const noexcept;
};
template <typename T>
using HashMap = std::unordered_map<AsnObjectIdentifier,
T,
AsnObjectIdentifierHasher,
AsnObjectIdentifierComparator>;
I strongly discourage the usage of a free-function to implement arithmetic and logical operators (especially when STL interface provides customization by means of template arguments). Functors (function objects) provide better isolation code and avoid scope problems (e.g., ADL).
== operator overloading with struct
If you overload a binary operator as a member function, then it should only take one argument. The first operand is the object the operator is called on (i.e. *this
); the second operand is the single function argument.
struct names {
//...
// better to pass by reference;
// make the function 'const' so it can be used on constant objects
bool operator==(names const & rhs) const {
return this->fname == rhs.lname;
}
};
Alternatively, you can overload it as a non-member function, with two arguments:
bool operator==(names const & lhs, names const & rhs) {
return lhs.fname == rhs.lname;
}
If this needed access to private members (which isn't the case in this example), then it would have to be a friend. You can define friends inside the class definition; in which case the code would look exactly the same as your example, only with friend
in front of the function declaration.
(Of course, this isn't a sensible definition of equality since it's not symmetric. Many algorithms will break if you can have a == b
but not b==a
, as you can with this definition. lhs.fname == rhs.fname && lhs.lname == rhs.lname
would make more sense.)
Related Topics
Why Is the Data Type Needed in Pointer Declarations
What Are the Rules Governing C++ Single and Double Precision Mixed Calculations
Rc.Exe No Longer Found in VS 2015 Command Prompt
Reference Invalidation After Applying Reverse_Iterator on a Custom Made Iterator
Why C++11 Compiler Support Still Requires a Flag
How to Multiply a 64 Bit Integer by a Fraction in C++ While Minimizing Error
How to Profile Multi-Threaded C++ Application on Linux
How to Force the Use of Cmov in Gcc and VS
Explicitly Initialize Dword to 1, But Debugger Shows Wildly Out of Range Value
How to Get Duration, as Int Milli's and Float Seconds from <Chrono>
Is There a Readable Implementation of the Stl
Calculating Execution Time in C++
Rodrigues into Eulerangles and Vice Versa
Techniques for Obscuring Sensitive Strings in C++
How to Remove Element Not at Top from Priority_Queue