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>());
Related
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. :-)
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.
I have a code in C++14. However, when I used it in C++11, it has an error at const auto. How to use it in C++11?
vector<vector <int> > P;
std::vector<double> f;
vector< pair<double, vector<int> > > X;
for (int i=0;i<N;i++)
X.push_back(make_pair(f[i],P[i]));
////Sorting fitness descending order
stable_sort(X.rbegin(), X.rend());
std::stable_sort(X.rbegin(), X.rend(),
[](const auto&lhs, const auto& rhs) { return lhs.first < rhs.first; });
C++11 doesn't support generic lambdas. That's what auto in the lambda's parameter list actually stands for: a generic parameter, comparable to parameters in a function template. (Note that the const isn't the problem here.)
Note: C++14 does support lambdas with auto, const auto, etc. You can read about it here.
You have basically two options:
Type out the correct type instead of auto. Here it is the element type of X, which is pair<double, vector<int>>. If you find this unreadable, a typedef can help.
std::stable_sort(X.rbegin(), X.rend(),
[](const pair<double, vector<int>> & lhs,
const pair<double, vector<int>> & rhs)
{ return lhs.first < rhs.first; });
Replace the lambda with a functor which has a call operator template. That's how generic lambdas are basically implemented behind the scene. The lambda is very generic, so consider putting it in some global utility header. (However do not using namespace std; but type out std:: in case you put it in a header.)
struct CompareFirst {
template <class Fst, class Snd>
bool operator()(const pair<Fst,Snd>& l, const pair<Fst,Snd>& r) const {
return l.first < r.first;
}
};
std::stable_sort(X.rbegin(), X.rend(), CompareFirst());
I know there is an accepted answer, but you can also use decltype in C++11 for this, it looks a bit messy...
stable_sort(X.rbegin(), X.rend(), [](decltype(*X.cbegin()) lhs, decltype(lhs) rhs) { return lhs.first < rhs.first; });
Use cbegin() here as you get the const correct value_type of the container.
Unfortunately, generic lambdas that take auto (whether const or not) is a C++14 only feature.
See here https://isocpp.org/wiki/faq/cpp14-language#generic-lambdas for some more details.
Alternatively you can directly use the value_type typedef of the container with a decltype, like
std::stable_sort(X.rbegin(), X.rend(),
[](const decltype(X)::value_type & lhs,
const decltype(X)::value_type & rhs)
{return lhs.first < rhs.first; }
);
const auto is not supported in C++11 as a lambda parameter (actually generic lambdas are not supported in C++11).
To fix:
using pair_type = std::pair<double, std::vector<int>>;
vector<pair_type> X;
std::stable_sort(X.rbegin(), X.rend(),
[](const pair_type&lhs, const pair_type& rhs)
{ return lhs.first < rhs.first; });
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))
I have vector of structures:
vector<Custom> myvec;
Custom is a structure:
struct Custom
{
double key[3];
};
How to sort myvec by key[0]. key[1] or key[2] using STL sort algorithm?
Write a custom comparator:
template <int i> struct CustomComp
{
bool operator()( const Custom& lhs, const Custom& rhs) const
{
return lhs.key[i]<rhs.key[i];
}
};
and then sort e.g. by using std::sort(myvec.begin(),myvec.end(),CustomComp<0>()); (this sorts by the first key entry)
Or with a more recent compiler (with c++0x lambda support):
std::sort(myvec.begin(), myvec.end(),
[]( const Custom& lhs, const Custom& rhs) {return lhs.key[0] < rhs.key[0];}
);
By using a a custom comparator.
struct CustomLess {
size_t idx;
CustomLess(size_t i) : idx(i) {}
bool operator()(Custom const& a, Custom const& b) const {
return a.key[idx] < b.key[idx];
}
};
then
std::sort(myvec.begin(), myvec.end(), CustomLess(1)); // for 1
Note: I did not use a template because, while using a template enables the compiler to optimize for that specific index, it prevents you from selecting the index at runtime, e.g. based on userinput, so it's less flexible/can't do as much as the nontemplated version. And as we all know, premature optimization is evil :)
I'm not sure why so many of the answers posted are focusing on functors. There is no need for a functor with the OP's stated requirement. Here are 2 non-functor solutions:
1: Overload operator< in the Custom class
bool Custom::operator< (const Custom& rhs)
{
return key[0] < rhs.key[0];
}
// can call sort(myvec.begin(), myvec.end());
2: Create a custom comparison function
template<int i> bool CustomLess(const Custom& lhs, const Custom& rhs)
{
return lhs.key[i] < rhs.key[i];
}
// can call sort(myvec.begin(), myvec.end(), CustomLess<0>);
bool CompareCustoms(const Custom& lhs, const Custom& rhs)
{
// Compare criteria here
return (lhs.key[0] < rhs.key[0]);
}
sort(myvec.begin(), myvec.end(), CompareCustoms);