Why "no match for 'operator<'" when I declared it? - c++

It works for the struct xy that I declared. Why doesn't the same pattern work for complex<int>?
#include <complex>
#include <set>
using namespace std;
struct xy {
int x, y;
};
bool operator< (const xy &a, const xy &b) {
return a.x < b.x;
}
bool operator< (const complex<int> &a, const complex<int> &b) {
return a.real() < b.real();
}
int main() {
xy q;
set<xy> s;
s.insert(q);
complex<int> p;
set< complex<int> > t; //If I comment out these two lines,
t.insert(p); //it compiles fine.
return 0;
}
The error message:
In file included from c:\m\lib\gcc\mingw32\4.8.1\include\c++\string:48:0,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\locale_classes.h:40,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\ios_base.h:41,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\ios:42,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\istream:38,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\sstream:38,
from c:\m\lib\gcc\mingw32\4.8.1\include\c++\complex:45,
from test.cpp:1:
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_function.h: In instantiation of 'bool less<>::operator()(const _Tp&, const _Tp&) const':
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_tree.h:1321:11: required from 'pair<> _Rb_tree<>::_M_get_insert_unique_pos(const key_type&)'
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_tree.h:1374:47: required from 'pair<> _Rb_tree<>::_M_insert_unique(_Arg&&)'
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_set.h:463:29: required from 'pair<> __cxx1998::set<>::insert(const value_type&)'
c:\m\lib\gcc\mingw32\4.8.1\include\c++\debug\set.h:220:59: required from 'pair<> __debug::set<>::insert(const value_type&)'
test.cpp:28:19: required from here
c:\m\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_function.h:235:20:
error: no match for 'operator<' (operand types are 'const std::complex<int>' and 'const std::complex<int>')
{ return __x < __y; }
My best guess is that this has something to do with complex<T> being a class, not a struct. By I can't see the logic of why that should make a difference. Or is it some template horribleness?
What I see happening is that the STL at some point tries (roughly speaking) to do a < b, where a and b are complex<int> instances. So it's looking for bool operator< (const complex<int> &a, const complex<int> &b). Well, there is exactly that declared just above main(). Why is it being unreasonable? I thought maybe it didn't like them being references. But removing the ampersands made no difference to its complaint.

One option is to write a custom comparison functor, and instantiate the set with this.
#include <complex>
#include <set>
bool operator< (const std::complex<int> &a, const std::complex<int> &b) {
return a.real() < b.real();
}
struct my_less {
bool operator() (const std::complex<int>& lhs, const std::complex<int>& rhs) const{
return lhs < rhs;
}
};
int main() {
std::complex<int> p;
std::set< std::complex<int>, my_less > t;
t.insert(p);
return 0;
}
Sample on Coliru

It works for the struct xy that I declared. Why doesn't the same pattern work for complex<int>?
The reason is that when you use types from namespace std only, like std::set and std::complex, the compiler has no reason to look for operators in any other namespaces.
With struct xy this is different, as the operator is declared together with the type.
And also, the current standard says:
The effect of instantiating the template complex for any type other than float, double, or long double is
unspecified.
So using complex<int> might, or might not, work depending on which compiler you use. "Unspecified" is not as bad as "undefined", but
of course not very reliable or portable.

As of today, I am facing this issue with my Ubuntu's g++. Suppose I have:
namespace X { namespace Y { class C { ... }; } }
Now operator== is recognized if it's defined in a global namespace, such as:
bool operator== (const X::Y::C& lhs, const X::Y::C& rhs) { return lhs == rhs; }
However, somehow compiler doesn't recognize operator<, if defined in the same way.
Now following way works well:
namespace X { namespace Y {
bool operator< (const C& lhs, const C& rhs) { return lhs < rhs; } } }
However, whether you should do it the same with expanding standard namespace std is a controversial topic. :-)

Related

specialize std::greater via std::rel_ops

How I can specialize std::greater by using std::rel_ops?
I have something like this
#include <utility>
#include <functional>
using namespace std::rel_ops;
struct MyStruct {
int field;
bool operator < (const MyStruct& rhs) const {
return field < rhs.field;
}
};
So I need to sort elements in descending order. How I can do it by using operator <, std::rel_ops and std::greater?
I'm assuming you tried to do something similar to
MyStruct ms[] = {{10}, {50}, {30}, {20}};
std::sort(std::begin(ms), std::end(ms), std::greater<MyStruct>{});
This fails to compile because no suitable operator> will be found. That's because std::greater relies upon ADL to find the operator overload, and ADL searches in associated namespaces. std::rel_ops is not an associated namespace for MyStruct. You can get everything to work by adding a using declaration to the same namespace as MyStruct so that the relevant operator> will be found.
using std::rel_ops::operator>;
Live demo
But this is ugly, and not a viable solution in general, so forget about std::rel_ops and use Boost.Operators as Barry suggests.
You'd have to do it this way:
std::vector<MyStruct> v{...};
std::sort(v.begin(), v.end(), [](const MyStruct& lhs, const MyStruct& rhs){
using namespace std::rel_ops;
return lhs > rhs;
});
Although std::rel_ops is pretty lame. It's easier to use boost::less_than_comparable, in which you just add the operators directly into MyStruct:
struct MyStruct
: boost::less_than_comparable<MyStruct> // <== adds operator>,
// operator>=,
// and operator<=
{
MyStruct(int i) : field(i) { }
int field;
bool operator<(const MyStruct& rhs) const {
return field < rhs.field;
}
};
And then you can sort it the obvious way:
std::sort(v.begin(), v.end(), std::greater<MyStruct>());
std::rel_ops generate the other comparisons from == and < so you first need to define at least <
bool operator<(const MyStruct & lhs, const MyStruct & rhs) {
return lhs.field < rhs.field;
}
Now rel_ops generate > so now you can use std::greater in std::sort
std::sort(begin(myVector), end(myVector), std::greater<MyStruct>());

Why standard containers use function templates instead of non-template Koenig operators

This question is inspired by Issue with std::reference_wrapper. Let' say, for example, operator< for std::vector. It's defined as a function template as
template< class T, class Alloc >
bool operator<( const vector<T,Alloc>& lhs,
const vector<T,Alloc>& rhs );
As a result, implicit conversion of function argument to the type of the corresponding function parameter is denied (basically because of its template nature). This greatly reduces the usefulness and convenience of std::reference_wrapper. For example, you cannot use std::sort on std::vector<std::reference_wrapper<std::vector<int>>>.
On the other hand, all the problems are solved only if operator< is defined as a non-template Koenig operator like
template <...>
class vector ... {
friend bool operator<(const vector& a, const vector& b) {...}
};
I'm wondering why the standard library has adopted the former approach instead of this?
Consider this code (A.h):
template <class T>
class A {
public:
T m_x;
friend bool operator<(const A & lhs, const A & rhs) {
return lhs.m_x < rhs.m_x;
}
};
And main.cpp:
#include "A.h"
namespace buddy {
bool operator<(const A<double> & lhs, const A<double> &rhs) {
return lhs.m_x > rhs.m_x;
};
}
using namespace buddy;
int main(int argc, char ** argv) {
A<double> a1;
A<double> a2;
a1 < a2;
return 0;
}
This code does not compile:
main.cpp:14:5: error: ambiguous overload for ‘operator<’ (operand types are ‘A’ and ‘A’)
a1 < a2;
The reason of course is that both of the operator<'s are exact matches. On the other hand, if we change the first operator< to (defined outside the class):
template <class T>
bool operator<(const A<T> & lhs, const A<T> & rhs) {
return lhs.m_x < rhs.m_x;
}
The compiler stops complaining: it's now a competition between an exact match, and a function template, so the exact match is used.
If operator< was defined in the fashion that you're suggesting, there would be no reasonable way for users of std::vector to redefine the behavior of operator<, short of specializing std::vector themselves, which is a lot more work.
In conclusion, the standard writers elected to make it easier to overload operator<, than to provide an operator< that might be more useful in certain situations. I think they made the right choice.

binary_search with std::pair using a custom operator

I am trying to do a binary_search including a vector of integer pairs and an integer as follows:
#include <vector>
#include <algorithm>
using namespace std;
typedef vector<pair<size_t,size_t> > int_pairs;
bool operator<(const size_t& l, const pair<size_t,size_t>& r)
{return r.first < l;} // useful for binary search
int main(){
int_pairs pairs_vec;
pairs_vec.push_back(pair <size_t,size_t>(1,2));
pairs_vec.push_back(pair <size_t,size_t>(2,2));
size_t i(2);
binary_search(pairs_vec.begin(),pairs_vec.end(),i);
}
The compiler tells me that the operator< is not defined:
erreur: no match for ‘operator<’ (operand types are ‘const long unsigned int’ and ‘std::pair<long unsigned int, long unsigned int>’)
Am I doing it the right way? I tried to change the definition of the operator in many different ways, but nothing seems to work.
The reason this doesn't work is that operator< isn't looked up from the point you call binary_search, but rather later from inside its body - and that's inside namespace std.
Since std::pair already defines relational operators in namespace std, these hide your overload in global scope and it's never found by name lookup.
The solution is to not use operator< at all. Create your own comparator class that doesn't clash with anything, overload its operator(), and use the other overload of binary_search that lets you specify custom comparator. Something like this:
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<size_t, size_t> my_pair;
typedef vector<pair<size_t,size_t> > int_pairs;
struct Comp {
// important: we need two overloads, because the comparison
// needs to be done both ways to check for equality
bool operator()(my_pair p, size_t s) const
{ return p.first < s; }
bool operator()(size_t s, my_pair p) const
{ return s < p.first; }
};
int main(){
int_pairs pairs_vec;
pairs_vec.push_back(pair <size_t,size_t>(1,2));
pairs_vec.push_back(pair <size_t,size_t>(2,2));
size_t i(2);
binary_search(pairs_vec.begin(),pairs_vec.end(),i, Comp());
}
Side notes:
Your attempt at operator< was wrong, because you switched the order of operands inside the function. The contract for comparators for strict weak ordering says that it must return true if first operand comes before the second (this goes for all comparison functions throughout the standard library).
bool operator<(const size_t& l, const pair<size_t,size_t>& r)
{
return r.first < l; // Wrong!
}
And as said above in the comment, if the operands for the comparison are of different types, you'll need two overloads. To check for equality with <, you need two test:
(!(a < b) && (!b < a))

How to write a comparison operator in c++?

I'm having an array of structure containing three fields:
struct data{
int s;
int f;
int w;
};
struct data a[n];
In order to sort the array of structure based on field f I'm using my own comparison operator :
bool myf( struct data d1,const struct data d2){
return d1.f < d2.f ;
}
The above operator works fine in inbuilt sort() function :
sort(a,a+n,myf);
but it's not working for upper_bound() function :
upper_bound(a,a+n,someValue,myf);
Can anyone tell me where am I doing wrong ? Is my comparison operator wrong ? If it's wrong, why is it working for sort() function and not upper_bound() ?
I'm getting following on compilation :
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘_FIter std::upper_bound(_FIter, _FIter, const _Tp&, _Compare) [with _FIter = data*, _Tp = int, _Compare = bool (*)(data, data)]’:
prog.cpp:37: instantiated from here
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:2243: error: conversion from ‘const int’ to non-scalar type ‘data’ requested
All you actually need here is to create operator< for your type:
inline bool operator<( const data& lhs, const data& rhs ) {
return lhs.f < rhs.f;
}
and standard algorithms will magically work for you.
In C++ you don't need struct when referring to a type like in C, and you want to pass by const reference to avoid copying.
Edit 0:
The above overloads standard comparison operator < for your type. You would use it implicitly as:
data values[N];
// ... populate
std::sort( values, values + N );
or explicitly with a standard functor:
std::sort( values, values + N, std::less<data>());
Edit 1:
See that compiler tells you _Tp = int in the warning? You need to pass an instance of data as third argument to upper_bound, not int:
data xxx = { 0, 1, 7 };
auto iter = std::upper_bound( values, values + N, xxx );
You can also create overloads for comparing to integers, like:
inline bool operator<( const data& lhs, int rhs ) {
return lhs.f < rhs;
}
inline bool operator<( int lhs, const data& rhs ) {
return lhs < rhs.f;
}
for your original invocation to work.
Primarily, it isn't working because the upper_bound overload that accepts a custom sorting takes four parameters:
// http://en.cppreference.com/w/cpp/algorithm/upper_bound
template< class ForwardIt, class T, class Compare >
ForwardIt upper_bound( ForwardIt first, ForwardIt last, const T& value,
Compare comp );
It was suggested in another answer that you introduce operator< for your type. However, do not do this just for the sake of one specific sorting. Only introduce comparison operators iff they actually make sense for your type.
If you don't follow this rule, future programmers might use your type and wonder about why something works that shouldn't, or vice versa. Your future evil twin may also want to use another sorting for his purpose.
E.g., it makes sense for a complex-datatype class, a SIMD-class (like std::valarray), but it doesn't make any specific sense for example for an Employee class:
Employee foo, bar;
if (bar > foo) {
// is bar taller than foo?
// is bar older than foo?
// is bar working better than foo?
// is bar bigger newbie than foo?
}
Instead, you could do it like this:
namespace employee_ordering {
struct by_name_ascending {
bool operator() (Employee const &lhs, Employee const &rhs) const {
return lhs.name() < rhs.name();
}
};
struct by_name_descending {
bool operator() (Employee const &lhs, Employee const &rhs) const {
return lhs.name() > rhs.name();
}
}
};
....
upper_bound(first, last, ..., employee_ordering::by_name_ascending());

How to use a lambda expression as a template parameter?

How to use lambda expression as a template parameter? E.g. as a comparison class initializing a std::set.
The following solution should work, as lambda expression merely creates an anonymous struct, which should be appropriate as a template parameter. However, a lot of errors are spawned.
Code example:
struct A {int x; int y;};
std::set <A, [](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
} > SetOfA;
Error output (I am using g++ 4.5.1 compiler and --std=c++0x compilation flag):
error: ‘lhs’ cannot appear in a constant-expression
error: ‘.’ cannot appear in a constant-expression
error: ‘rhs’ cannot appear in a constant-expression
error: ‘.’ cannot appear in a constant-expression
At global scope:
error: template argument 2 is invalid
Is that the expected behavior or a bug in GCC?
EDIT
As someone pointed out, I'm using lambda expressions incorrectly as they return an instance of the anonymous struct they are referring to.
However, fixing that error does not solve the problem. I get lambda-expression in unevaluated context error for the following code:
struct A {int x; int y;};
typedef decltype ([](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
}) Comp;
std::set <A, Comp > SetOfA;
The 2nd template parameter of std::set expects a type, not an expression, so it is just you are using it wrongly.
You could create the set like this:
auto comp = [](const A& lhs, const A& rhs) -> bool { return lhs.x < rhs.x; };
auto SetOfA = std::set <A, decltype(comp)> (comp);
For comparators used this way, you're still better off with a non-0x approach:
struct A { int x; int y; };
struct cmp_by_x {
bool operator()(A const &a, A const &b) {
return a.x < b.x;
}
};
std::set<A, cmp_by_x> set_of_a;
However, in 0x you can make cmp_by_x a local type (i.e. define it inside a function) when that is more convenient, which is forbidden by current C++.
Also, your comparison treats A(x=1, y=1) and A(x=1, y=2) as equivalent. If that's not desired, you need to include the other values that contribute to uniqueness:
struct cmp_by_x {
bool operator()(A const &a, A const &b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
};
Not sure if this is what you're asking, but the signature of a lambda which returns RetType and accepts InType will be:
std::function<RetType(InType)>
(Make sure to #include <functional>)
You can shorten that by using a typedef, but I'm not sure you can use decltype to avoid figuring out the actual type (since lambdas apparently can't be used in that context.)
So your typedef should be:
typedef std::function<bool(const A &lhs, const A &rhs)> Comp
or
using Comp = std::function<bool(const A &lhs, const A &rhs)>;
the problem is the last template parameter is type not an object, so you might want to do the following
std::set <A, std::fuction<bool(const A &,const A &)>>
SetOfA([](const A lhs, const A &rhs) ->bool {
return lhs.x < rhs.x;
} > SetOfA;
to make it simpler you can do the following:
auto func = SetOfA([](const A lhs, const A &rhs) ->bool { return lhs.x < rhs.x;}
set <A,decltype(func)> SetOfA(func);
cheers