Upper and lower bounds of inconsistency

I saw what looks like inconsistency in the syntaxes of std :: lower_bound () and std :: upper_bound () (well, actually, type conversion), and I was wondering if anyone could explain this? According to the comments, line 2 will not compile, despite the obvious similarity with line 1; you need to use the form shown in line 3 (on gcc 4.7.3 / ubuntu at least 64 bits), that's all I have to play with)

#include <set> #include <algorithm> using namespace std; class MyInt { private: int val; public: MyInt(int _val): val(_val) {} bool operator<(const MyInt& other) const {return val < other.val;} }; int main() { set<MyInt> s; s.insert(1); // demonstrate implicit conversion works s.insert(MyInt(2)); s.insert(3); // one last one for the road set<MyInt>::iterator itL = lower_bound(s.begin(), s.end(), 2); //LINE 1 // the line below will NOT compile set<MyInt>::iterator itU = upper_bound(s.begin(), s.end(), 2); //LINE 2 // the line below WILL compile set<MyInt>::iterator itU2 = upper_bound(s.begin(), s.end(), MyInt(2)); // LINE 3 return 0; } 
+5
source share
1 answer

I do not think this is a mistake. If you look at the (possible) implementation of std::upper_bound , the comparison is performed as

 if (!(value < *it)) { ... } // upper_bound, implicit conversion `MyInt`->`int` doesn't work 

And since operator< is a member function of MyInt (and not an int , which is not a class type), the code does not compile, since there is no conversion from MyInt to int . On the other hand, in std::lower_bound , *it appears on lhs comparisons, and value (of type int ) can be implicitly converted to MyInt when passed to MyInt::operator< .

 if (*it < value) { ... } // lower_bound, implicit conversion `int`->`MyInt` works 

It is for this reason that it is better to implement comparison operators as non-members, so you do not have this asymmetry. This is also mentioned in the Scott Meyers C ++ Effect book: Clause 24: Declare non-member functions when type conversions should be applied to all parameters.

Quick and dirty fix: specify MyInt::operator int(){return val;} to implicitly convert MyInt to int . ( EDIT: not working, ambiguity). What works by eliminating the need for implicit conversion

 set<MyInt>::iterator itU = upper_bound(s.begin(), s.end(), MyInt(2)); 

instead.

+5
source

Source: https://habr.com/ru/post/1235505/


All Articles