C++11 using std::equal_range with custom comparison function - c++

Consider this example
(Note that this is just something I made up to illustrate the problem. I am well aware there are more efficient ways to parse an arithmetic expression and though the subject is fascinating, this has nothing to do with my actual question. It's just a semi-realistic example, if I might say so.
I agree the parser thing might make the question seem more complicated, but I could not think of a more abstract example).
Assume you want to do a simple expression parser. You will get bits of strings from a tokenizer, some of them being possibly ambiguous.
For instance, the string "-" could represent an unary minus or a binary minus.
Assume you want to get all possible meanings for string "-".
You could do as follows:
1) define a sorted array describing all possible operators
// types of operators
enum class opType: char { unary, lasso, rasso, none };
// operator descriptors
struct opDesc {
string symbol;
opType type;
char priority;
// partial order comparison
bool operator< (const opDesc& a) const
{
// unary operators first
if (symbol == a.symbol) return type < a.type;
return symbol < a.symbol;
}
// comparison with strings
static bool comp_desc_str (const opDesc& a, const string& s)
{
return a.symbol < s;
}
static bool comp_str_desc (const string& s, const opDesc& a)
{
return s < a.symbol;
}
};
static opDesc op_descriptors[] = {
{ "+" , opType::unary, 8 }, // unary +
{ "-" , opType::unary, 8 }, // unary -
{ "*" , opType::lasso, 6 }, // multiplication
{ "/" , opType::lasso, 6 }, // division
{ "+" , opType::lasso, 5 }, // addition
{ "-" , opType::lasso, 5 }, // substraction
};
2) use std::equal_range to get all possible matches for a given string
// sort descriptors by value and type
sort(begin(op_descriptors), end(op_descriptors));
// do some searches
string patterns[] = { "+", "-", ">>", "**" };
for (string s : patterns)
{
pair<opDesc*, opDesc*> ops;
ops = equal_range(
std::begin(op_descriptors),
std::end (op_descriptors),
s,
opDesc::comp_desc_str);
cout << s <<": "<< ops.first[0] << ops.second[-1] << endl;
}
This code won't compile, complaining about opDesc::comp_desc_str (it expects parameters the other way around, i.e. string first, opDesc next).
If I try to replace the function with a version that takes its arguments in reverse order:
ops = equal_range(
std::begin(op_descriptors),
std::end (op_descriptors),
s,
opDesc::comp_str_desc);
it won't compile either, complaining about parameters being yet again in the wrong order (at some other point of the algorithm).
This code, however, will work (see a live version here)
#include <regex>
#include <iostream>
using namespace std;
// types of operators
enum class opType: char { unary, lasso, rasso, none };
// operator descriptors
struct opDesc {
string symbol;
opType type;
char priority;
// partial order comparison
bool operator< (const opDesc& a) const
{
// unary operators first
if (symbol == a.symbol) return type < a.type;
return symbol < a.symbol;
}
// comparison with strings
static bool comp_desc_str (const opDesc& a, const string& s)
{
return a.symbol < s;
}
static bool comp_str_desc (const string& s, const opDesc& a)
{
return s < a.symbol;
}
// display
friend ostream& operator<<(ostream& os, const opDesc& op);
};
ostream& operator<<(ostream& os, const opDesc& op)
{
os << op.symbol << "[" << (int)op.type << ":" << (int)op.priority << "]";
return os;
}
static opDesc op_descriptors[] = {
{ "+" , opType::unary, 8 }, // unary +
{ "-" , opType::unary, 8 }, // unary -
{ "~" , opType::unary, 8 }, // bitwise not
{ "**", opType::rasso, 7 }, // power
{ "*" , opType::lasso, 6 }, // multiplication
{ "/" , opType::lasso, 6 }, // division
{ "%" , opType::lasso, 6 }, // remainder
{ "+" , opType::lasso, 5 }, // addition
{ "-" , opType::lasso, 5 }, // substraction
{ "<<", opType::lasso, 4 }, // left shift
{ ">>", opType::lasso, 4 }, // right shift
{ "&" , opType::lasso, 3 }, // bitwise and
{ "^" , opType::lasso, 2 }, // bitwise xor
{ "|" , opType::lasso, 1 }, // bitwise or
{ "(" , opType::none , 0 }, // braces
{ ")" , opType::none , 0 }
};
int main(void)
{
// sort descriptors by value and type
sort(begin(op_descriptors), end(op_descriptors));
// do some searches
string patterns[] = { "+", "-", ">>", "**" };
for (string s : patterns)
{
pair<opDesc*, opDesc*> ops;
// this won't work
/*
ops = equal_range(
std::begin(op_descriptors),
std::end (op_descriptors),
s,
opDesc::comp_desc_str or opDesc::comp_str_desc);
*/
// this works
ops.first = lower_bound(
std::begin(op_descriptors),
std::end (op_descriptors),
s, opDesc::comp_desc_str);
ops.second = upper_bound(
std::begin(op_descriptors),
std::end (op_descriptors),
s, opDesc::comp_str_desc);
cout << s <<": "<< ops.first[0] << ops.second[-1] << endl;
}
}
output:
+: +[0:8]+[1:5] // unary and binary "-" operators found
-: -[0:8]-[1:5] // same thing for "+"
>>: >>[1:4]>>[1:4] // first == second when there is only
**: **[2:7]**[2:7] // one version of the operator
I tried this code on VisualC++ 2013 and g++ with the same results
(only the obfuscation of the template error messages vary).
Questions
is there a particular reason why lower_bound and upper_bound should require two different custom comparison functions?
is there a workaround for MSVC throwing a bogus error in debug build when using functors to work around the problem?
is there a definite workaround for this problem (i.e. using equal_range as intended instead of doing the job twice and make it compile in debug mode on Visual C++ 2013)?

std::lower_bound requires comp(*it, val) whereas std::upper_bound requires comp(val, *it).
So your comp functor have to provide both bool operator () (const opDesc& a, const string& s) const and bool operator ()(const string& s, const opDesc& a) const.
So, you may use following comp functor:
struct lessOpDescWithString
{
bool operator () (const opDesc& lhs, const std::string& rhs) const {
return opDesc::comp_desc_str(lhs, rhs);
}
bool operator () (const std::string& lhs, const opDesc& rhs) const {
return opDesc::comp_str_desc(lhs, rhs);
}
};

My own answer, only summarizing other contributions, notably Jarod42's:
Why the two comparisons
The algorithm of equal_range requires both > and < comparisons between internal (opDesc in this example) and foreign (std::string) types.
You can't deduce a<b from !(b<a), because of the == case, so you have to provide two different comparators.
Functionnally, you could pick any working combination of comparison operations, for instance < and > or < and <=, but the std:: guys settled for a fixed < comparison with arguments swapped around, which is a choice dictated by the signature of the function: it only has to define a (type, foreign type) and a (foreign type, type) variant.
lower_bound only requires < (expressed as type < foreigh type) while upper_bound only requires > (expressed as foreign type < type), so both can work with a single function, but equal_range must have access to both prototypes.
The way to do it
The practical solution is to define a function object aka functor to do the job:
// operator descriptors
struct opDesc {
string symbol;
opType type;
char priority;
// partial order comparison
bool operator< (const opDesc& a) const
{
// unary operators first
if (symbol == a.symbol) return type < a.type;
return symbol < a.symbol;
}
// functor to compare with strings
struct comp
{
bool operator() (const opDesc& a, const std::string& b) const
{
return a.symbol < b;
}
bool operator() (const std::string& a, const opDesc& b) const
{
return a < b.symbol;
}
};
and use it like so:
pair<opDesc*, opDesc*> ops;
ops = equal_range(
std::begin(op_descriptors),
std::end (op_descriptors),
s,
opDesc::comp()); // <- functor to provide two different comparison functions
MSVC bug
Besides, this won't compile on MSVC++ 2013 due to an obscure paranoid check enabled only in debug mode. The release version will compile fine, as will the code in g++ regardless of debug level.
Judging from the cryptic names used, it seems the template checks whether the comparison defines a total order (which it shouldn't since the whole point of this API is to work on partially ordered structures).
My current (ugly) workaround is to disable some internal debug flag:
#if (defined _MSC_VER && defined _DEBUG)
#define _ITERATOR_DEBUG_LEVEL 1
#endif // _MSC_VER && _DEBUG
prior to including std:: headers
Another possible workaround suggested by Jarod42 is to define the missing comparison function.
// functor to compare with strings
struct comp
{
bool operator() (const opDesc& a, const std::string& b)
{ return a.symbol < b; }
bool operator() (const std::string& a, const opDesc& b)
{ return a < b.symbol; }
// just to make Microsoft Visual C++ happy when compiling in debug mode
bool operator() (const opDesc& a, const opDesc& b)
{ assert(false); return false; }
};

I suppose that std::lower_bound and std::upper_bound will use a binary search on your sorted array and must be able to compare obDesc to std::string and vice versa. I would suggest making a comparator like
struct obDescStrCmp {
bool operator()(const opDesc& lhs, const opDesc& rhs) const {
// code to compare obDesc to opDesc
}
bool operator()(const opDesc& lhs, const std::string& rhs) const {
// code to compare obDesc to std::string
}
bool operator()(const std::string& lhs, const opDesc& rhs) const {
// code to compare std::string to opDesc
}
bool operator()(const std::string& lhs, const std::string& rhs) const {
// code to compare std::string to std::string
// I'm not sure if this is really necessary.
}
};
and pass it to your std algorithm of choice instead of relying on the operators defined in your opDesc struct. The compiler should select the correct overload based on the actual order of parameters in the implementations of the std algorithms.
Edit: Replace operator< with operator() to make the struct callable.

Related

incorrect function call on overload operator

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

std::initializer_list as right hand argument for overloaded operator?

I want to use something like the "in" operator available in other programming languages. I read many posts about that already. But, nothing that fits my needs.
What I wanted to do is a little bit different. Please see the following first example:
#include <iostream>
#include <initializer_list>
#include <algorithm>
bool operator ==(const int lhs, std::initializer_list<int>& il) {
return std::find(il.begin(), il.end(), lhs) != il.end();
}
int main() {
std::initializer_list<int> il{1,2,3,4,5};
std::cout << (3 == il) << '\n';
// std::cout << (3 == {1,2,3,4,5}) << '\n'; // Does not compile
}
But this does not compile. Presumably, because an initalizer list is no expression. Although there are exceptions. A std::initializer_list maybe a function parameter, although also here expressions are expected.
And since any operator is basically also a function, my hope was, that I also can use std::initalizer_list as argument.
But I cannot.
I tried the same approach by defining an own operator with a name by misusing overloading of 2 operators. See below:
#include <iostream>
#include <vector>
// New operator: is_in
enum { is_in };
int operator < (const int& lhs, decltype(is_in)) { return lhs; }
int operator > (int lhs, std::vector<int>& rhs) { return std::find(rhs.begin(), rhs.end(), lhs) != rhs.end();}
int operator > (int lhs, std::initializer_list<int>& rhs) { return std::find(rhs.begin(), rhs.end(), lhs) != rhs.end(); }
int main() {
std::vector validValues{ 1, 2, 3, 4, 5 };
bool b = (5 <is_in> validValues);
// bool b = (5 <is_in> { 1, 2, 3, 4, 5 }); // Does not compile
std::cout << b << '\n';
}
Same principle, same problem . . .
Is there any way to make this happen?
Brace init lists are only allowed in certain contexts by exceptions to the grammar. And while an overloaded operator involves a function call, it must still obey the standard grammar rules unless you invoke it by name (operator#) in a function call.
So your named operator can work, but you must overload one of the operators for which an exception exists1. A rough summary of those overloadable operators is:
Assignment, including compound assignment (operator=, operator +=).
Index (operator[]).
Function call (operator()).
None of those may be overloaded as a non-member, so getting symmetry (<is_in> or =is_in=), is not possible. But if forego that, we can do something like
#include <iostream>
#include <initializer_list>
inline constexpr class op {
template<typename T>
friend auto operator< (T const& t, op) {
struct {
T const & t;
bool operator=(std::initializer_list<T> il) {
return std::find(il.begin(), il.end(), t) != il.end();
}
} ret{t};
return ret;
}
} is_in;
int main() {
bool b = (5 <is_in= { 1, 2, 3, 4, 5 });
std::cout << b << '\n';
}
Which is not too pretty... I guess we can choose another operator instead of operator< to perhaps improve the look of this, but it seems like folly in general. This is already a bit too obscure.
1 - On that front, you should know that overloading operators whose parameters are purely standard types is ill-advised. The standard can change the library definition at any time and break your code gloriously.
You need to take the initializer_list by const&:
bool operator==(const int lhs, const std::initializer_list<int>& il)
std::cout << (3 == std::initializer_list{1,2,3,4,5}) << '\n';
For the is_in test you could overload the comma operator and do something like this:
template<class T>
struct is_in {
is_in(const std::initializer_list<T>& il) : ref(il) {}
const std::initializer_list<T>& ref;
};
template<class T>
bool operator,(const T& lhs, const is_in<T>& rhs) {
return std::find(rhs.ref.begin(), rhs.ref.end(), lhs) != rhs.ref.end();
}
int main() {
bool b = (5, is_in{ 1, 2, 3, 4, 5 });
std::cout << b << '\n';
}

std::set custom comparator for non null strings

As the title suggests am trying to implement comparison functor for my defined structure. Here is the sample snippet
#include<set>
struct testData
{
char * data;
int size;
};
class compare
{
public:
bool operator()(const testData & lhs,
const testData & rhs) const noexcept
{
return memcmp(lhs.data, rhs.data, lhs.size<rhs.size?lhs.size:rhs.size) < 0;
}
};
int main()
{
std::set<testData,compare>S;
....
return 0;
}
Issue in the comparison function is since am taking lesser size,this
case fails
suppose there is already this data present {"test",4},and i am trying
to find {"test1",5}.it will say as matched.How can i modify comparison
to overcome this?
Update:
changed to this
class compare
{
public:
bool operator()(const testData & lhs,
const testData & rhs) const noexcept
{
if (lhs.size == rhs.size)
return memcmp(lhs.data, rhs.data, lhs.size) < 0;
return lhs.size < rhs.size;
}
};
will this work?
You'd use std::lexicographical_compare.
Lexicographical comparison is a operation with the following properties:
Two ranges are compared element by element.
The first mismatching element defines which range is lexicographically less or greater than the other.
If one range is a prefix of another, the shorter range is lexicographically less than the other.
If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
An empty range is lexicographically less than any non-empty range.
Two empty ranges are lexicographically equal.
class compare
{
public:
bool operator()(const testData & lhs,
const testData & rhs) const noexcept
{
return std::lexicographical_compare(lhs.data, lhs.data + lhs.size, rhs.data, rhs.data + rhs.size);
}
};
the reason it failes is because you compare only the length of the smaller string.
In your example only the "test" part of "test1" will be compared.
You can try this:
bool operator()(const testData & lhs,
const testData & rhs) const noexcept
{
int ret = memcmp(lhs.data, rhs.data, lhs.size<rhs.size?lhs.size:rhs.size);
return ret == 0 ? lhs.size < rhs.size : ret < 0 ;
}

c++ operator overload with string comparing

hello i have problem in my school c++ lab, my bool operator > should be return true if lhs is greater than rhs, however it always return false. i try print out lhs.tostring(), it show the number correctly.
my lhs and rhs is a string value.
due to some confidence restrict from my school work, i am not allow to post all the function of my work.
Updated information: ithis lab only can use c++14 and can't include any additional lib. The int value is written in string, and need to compare which is bigger. Assuming there is no negative and any letter other than number
some part of my header file
#include <cstring>
#include <iostream>
namespace CS170
{
class BigNum
{
public:
/* Constructor of BigNum object.
Takes in a character string and
constructs a BigNum */
BigNum(const char * rhs = "0");
/* one of rule of 3 need destructor */
~BigNum();
/* Return a character pointer pointing
to the start of the array representing the big num */
const char * toString() const;
/* Return how many digits the number has */
size_t getNumDigits() const;
BigNum & operator =(const BigNum & rhs);
private:
size_t len;
char* num;
};
}
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs);
cpp
namespace CS170
{
BigNum::BigNum(const char * rhs )
:len{strlen(rhs)}, num{new char[len+1]}
{
strcpy(num,rhs);
}
BigNum::~BigNum()
{
}
const char * BigNum::toString() const
{
return num;
}
size_t BigNum::getNumDigits() const
{
return len;
}
}
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs)
{
CS170::BigNum left_value{lhs};
CS170::BigNum right_value{rhs};
std::cout << std::endl;
std::cout << left_value.toString() << " " << right_value.toString() <<
std::endl;
/*this don't work for comparing**/
if(left_value.toString() > right_value.toString())
return true;
else
return false;
}
left_value.toString() > right_value.toString()
This does not do what you think it does. toString() returns a const char*, a pointer to some data. Formally the behaviour of > in your case is undefined since the pointers are not part of the same array, and even if they were, the result would not depend on the string contents.
To check the lexicogrammatical order of strings, you should use the right tool for it, for instance std::string::operator>:
std::string lhs_string{left_value.toString()};
std::string rhs_string{rght_value.toString()};
if (lhs_string > rhs_string)
// ...
// note: here you could simply do return lhs_string > rhs_string;
If you're using a recent compiler and C++17 is an option, you could also use those tools without copying data around:
#include <string_view>
const char* lhs = "programming";
const char* rhs = "language";
std::string_view lhs_string{lhs};
std::string_view rhs_string{rhs};
lhs_string>rhs_string // lexicogrammatical order
live demo
const char* cannot be compared in the way you are trying to. You have to use strcmp. Example usage would look like:
if (strcmp(left_value.toString(), right_value.toString()) > 0)
{
return true;
}
The last part of the function could even be simplified to:
return strcmp(left_value.toString(), right_value.toString()) > 0;
is nearly there but i don't work if compare 11 > 2, as is still read only the first string.
bool operator >(const CS170::BigNum &lhs, const CS170::BigNum &rhs)
{
CS170::BigNum left_data{lhs};
CS170::BigNum right_data{rhs};
int result = strncmp(left_data.toString(), right_data.toString(),20);
return result > 0;
}

Multiple Overloading of Operators

as you can see from the code I want to overload the < operator twice. 1 to sort by dist and the other by nodeID. I would like to check if there is any way to call the different overloaded methods. For example in the compLoc method, when I use the sort() method I want it to be sorted by nodeID but in other methods I want it to be sorted by dist.
struct AttSet{
int nodeID;
double dist;
bool operator < (const AttSet & str) const{
return (dist < str.dist);
}
/*
bool operator <(const AttSet & str){
return (nodeID < str.nodeID);
*/
bool operator == (const AttSet & str){
return nodeID == str.nodeID;
}};
void compLoc(Edge *edge, vector<Node*> &vertices){
int l = edge->length;
int vl = edge->head->nodeID;
int vr = edge->tail->nodeID;
/*
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end());
sort(vertices[vr]->attSet.begin(), vertices[vr]->attSet.end());
vector<AttSet> vInterSec;
set_intersection(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), vertices[vr]->attSet.begin(), vertices[vr]->attSet.end(), back_inserter(vInterSec));
*/}
You cannot have overloads that have the same signature. This holds for any function. How would you try to decide which version to use?
If you want sort the object based on different criteria you should use the sort version that takes a custom comparer function as the third argument.
Edit:
Of course you need to provide the comparer. I would suggest providing the comparers as static functions of the class if you have such power. This way you will not pollute enclosing namespace and you can access privates of the class with out exposing any getters. Since your properties are public the lambda would suffice, and probably be the best/cleanest approach.
Feeling adventurous I made a simple c++11 exercise program. For what it's worth, if you ever decided to go for proper encapsulation, I've shown both approaches:
#include <iostream>
#include <algorithm>
#include <vector>
#include <initializer_list>
#include <cassert>
using namespace std;
template<typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& v){
for(const auto& el : v){
out << el << '\n';
}
return out;
}
class A {
int a;
int b;
public:
A(std::initializer_list<int> l){
assert(l.size() == 2);
auto i = l.begin();
a = *i;
++i;
b = *i;
}
friend std::ostream& operator<<(std::ostream& stream, const A& e){
return stream << e.a << ' ' << e.b;
}
static bool compareViaA(const A& lhs, const A& rhs){
return rhs.a > lhs.a;
}
static bool compareViaB(const A& lhs, const A& rhs){
return rhs.b > lhs.b;
}
};
int main() {
std::vector<A> v {{2,3}, {3,2}, {1,4}, {4,1}};
//sort(v.begin(), v.end(), [](const A& a, const A& b){return a.a > b.a;}) // fails because of privacy violation
sort(v.begin(), v.end(), A::compareViaA);
std::cout << v << '\n';
sort(v.begin(), v.end(), A::compareViaB);
std::cout << v << '\n';
return 0;
}
Live: http://ideone.com/lDMujx.
I think you can implement this by using functor and take the comparator(operator< overload) outside the AttSet.
Here is a simple example:
struct AtrComparator {
bool distcmp;
AttrComparator(bool distcmp): distcmp(distcmp) {}
bool operator() (const AttSet &s1, const AttSet &s2) {
if(distcmp) {
return s1.dist < s2.dist;
} else {
return s1.nodeID < s2.nodeID;
}
}
}
And then you can do the sort through different feed, dist or nodeID.
.e.g:
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(true));
sort(vertices[vl]->attSet.begin(), vertices[vl]->attSet.end(), AttComparator(false));
You can't do that. They have the same signature exactly.
Use a functor or a lambda and pass it to whatever algorithm you want.
std::sort(std::begin(container), std::end(container),
[](const element_type& lhs, const element_type& rhs) { return ...; });
Another way to do this:
struct compare_by_node_id {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.nodeID < rhs.nodeID;
}
};
struct compare_by_dist {
bool operator()(const AttSet& lhs, const AttSet& rhs) const {
return lhs.dist < rhs.dist;
}
};
And you could pass that to the algorithm like:
std::sort(std::begin(container), std::end(container), compare_by_node_id());
you cannot do that because compiler doesn't see difference between:
bool operator < (const AttSet & str) const; //this const doesn't allow to override any property of object(instance of AttSet) if I remember
and
bool operator < (const AttSet & str);
there're the same same return type, same parameter (same signature)
compiler cannot choose which one is better
There's not a great way to do this as far as I am aware, since the compiler will see these as the exact same and will throw an error. If you need to do this, use the < operator as whatever will occur the most often, and then write a method that you can call to compare two object. Something like this:
bool operator< (const Blah &blah) const {
return (most often operation)
}
bool Blah::other_operation(const Blah &blah) const {
return (other operation)
}