Say I have got a plain old data (POD) struct
containing multiple numeric fields.
I want to overload the comparison operators so that I can compare two instances of my POD.
The problem is that I need an overload for those operators - say, operator less()
- for each of the numerical fields in the POD.
Obviously, the below does not work because the compiler has no way to pick the two versions apart:
struct my_struct{
int a;
int b;
int c;
};
bool operator<(const my_struct& one, const my_struct& two) {
return one.a < two.a;
}
bool operator<(const my_struct& one, const my_struct& two) {
return one.b < two.b;
}
So I wrote my own custom function lessThan()
, which accepts a flag and does the job, but I don't particularly like this solution (in MWE below) as I cannot use <
as I easily would with a comparison operator.
#include <iostream>
#include <iomanip>
struct my_struct{
int a;
int b;
int c;
};
bool lessThan(const my_struct& one, const my_struct& two, const char flag) {
switch (flag) {
case 'a':
return one.a < two.a;
break;
case 'b':
return one.b < two.b;
break;
case 'c':
return one.c < two.c;
break;
default:
throw("Either case a, b, or c\n");
break;
}
}
int main()
{
my_struct one{1, 3, 4};
my_struct two{2, 2, 4};
std::cout << "one < two: " << std::boolalpha
<< lessThan(one, two, 'a') << std::endl;
return 0;
}
Is there a way to somehow create multiple comparison operator overloads for custom POD struct
s with many numerical fields, with each overload comparing one of those fields?
(To give you more context, I need those overloads for sorting an array of files according to any of their characteristics: such as by dimension, by last modification date, by number of contained files or subdirectories, etc.
In the simplified example above, each POD instance abstracts a file.)
EDIT:
Sketch of intended usage:
sortAccordingToFieldA(std::vector<my_struct>& my_vec, int a){
for (auto i : my_vec) {
for (auto j : [std::find(my_vec.begin(), my_vec.end(), i)+1, my_vec.end()] ) {
if (i < j) // here '<' is overloaded according to field 'a'
// sorting operations
}
}
}
SECOND EDIT
Answer and comments here helped in completing this task
In your "intended usage" example, my_vec.begin()+i+1
makes no sense, as i
is a my_struct
instance in the vector, it is not an index of the vector. A range-for
loop does not use indexes, it uses iterators.
In any case, since your function is named sortAccordingToFieldA()
then just access field a
directly, eg:
void sortAccordingToFieldA(std::vector<my_struct>& my_vec){
for (auto i = my_vec.begin(); i != my_vec.end(); ++i) {
for (auto j = i+1; j != my_vec.end(); ++j) {
if (i->a < j->a) {
// sorting operations
}
}
}
}
Repeat for sortAccordingToFieldB()
and sortAccordingToFieldC()
functions, accordingly.
If you really want a single function that is more generic, then you have a couple of choices:
pass in a pointer-to-member so the caller can specify which field to compare, eg:
void sortAccordingToField(std::vector<my_struct>& my_vec, int my_struct::* field){
for (auto i = my_vec.begin(); i != my_vec.end(); ++i) {
for (auto j = i+1; j != my_vec.end(); ++j) {
if ((*i).*field < (*j).*field) {
// sorting operations
}
}
}
}
sortAccordingToField(my_vec, &my_struct::a);
sortAccordingToField(my_vec, &my_struct::b);
sortAccordingToField(my_vec, &my_struct::c);
pass in a comparison function/lambda so the caller can decide how to compare the items, eg:
template <typename Comparer>
void sortAccordingToCompare(std::vector<my_struct>& my_vec, Comparer compare) {
for (auto i = my_vec.begin(); i != my_vec.end(); ++i) {
for (auto j = i+1; j != my_vec.end(); ++j) {
if (compare(*i, *j)) {
// sorting operations
}
}
}
}
sortAccordingToCompare(my_vec, [](auto& i, auto& j){ return i.a < j.a; });
sortAccordingToCompare(my_vec, [](auto& i, auto& j){ return i.b < j.b; });
sortAccordingToCompare(my_vec, [](auto& i, auto& j){ return i.c < j.c; });