Overloaded operators for std::bind placeholders - c++

boost::bind overloads several operators for its placeholders:
For convenience, the function objects produced by bind overload the logical not operator ! and the relational and logical operators ==, !=, <, <=, >, >=, &&, ||.
For example, this allows me to pass _1 == desired_value as a predicate to STL algorithms.
Unfortunately, std::bind does not seem to overload these operators :(
Why is that?
What is a good workaround to simulate _1 == desired_value with std::bind?

IIRC, Boost.Bind only overloads those operators for the placeholders because the original Boost Lambda Library, which Boost.Bind is an improvement of, did (Boost.Bind is obsolete thanks to Boost.Phoenix, btw). std::bind's placeholders are only intended for exactly that purpose, as placeholders for arguments to std::bind.
As a workaround, use polymorphic functors:
struct compare_equal{
template<class LHS, class RHS>
bool operator()(LHS&& lhs, RHS&& rhs){ // assume bool return
return std::forward<LHS>(lhs) == std::forward<RHS>(rhs);
}
};
// ...
auto bound = std::bind(compare_equal(), _1, desired_value);
Live example on Ideone.

You could always overload these operators for the placeholders yourself, for example operator<:
struct less12
{
template<typename T, typename U>
bool operator()(const T& a, const U& b) const
{
return a < b;
}
};
less12 operator<(decltype(_1), decltype(_2))
{
return less12();
}
struct less21
{
template<typename U, typename T>
bool operator()(const U& b, const T& a) const
{
return a < b;
}
};
less21 operator<(decltype(_2), decltype(_1))
{
return less21();
}
template<typename T>
struct lessa1
{
const T& a;
template<typename U>
bool operator()(const U& b) const
{
return a < b;
}
};
template<typename T>
lessa1<T> operator<(const T& a, decltype(_1))
{
lessa1<T> result = {a};
return result;
}
template<typename U>
struct less1b
{
const U& b;
template<typename T>
bool operator()(const T& a) const
{
return a < b;
}
};
template<typename U>
less1b<U> operator<(decltype(_1), const U& b)
{
less1b<U> result = {b};
return result;
}
Here is a usage example, compared with binders (custom less12 vs std::less) and lambda syntax:
template<typename Iterator>
void quicksort(Iterator begin, Iterator end)
{
// ...
auto m = std::partition(begin + 1, end, _1 < *begin);
auto m = std::partition(begin + 1, end, std::bind(less12(), _1, *begin));
auto m = std::partition(begin + 1, end, std::bind(std::less<typename std::iterator_traits<Iterator>::value_type>(), _1, *begin));
auto m = std::partition(begin + 1, end, [begin](const typename std::iterator_traits<Iterator>::value_type& x) { return x < *begin; } );
// ...
}
Really looking forward to N3421 and polymorphic lambdas here :)

std::bind does not seem to overload these operators?
Why is that?
Because C++11 added lambdas which provide the same, if not better, conveniences to produce anonymous functor objects.
What is a good workaround to simulate _1 == desired_value with std::bind?
std::bind is not used to simulate the behavior. Use C++11 lambdas to implement the answer to your question:
std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), [](int i) -> bool { return i == desired_value; });
Please note that you don't need the "-> bool" syntax if you are using a fairly recent compiler that can derive the return type.
If you don't want to or can't use C++11 lambdas, then you can create a non-anonymous functor like this:
bool IsDesiredValue (int i) {
return (i == desired_value);
}
std::vector<int>::iterator i = std::find_if (myvector.begin(), myvector.end(), IsDesiredValue);
For another example, here is a use of C++11 lambdas being used to create an anonymous functor to sort a vector by a value of a type:
std::sort(myVector.begin(), myVector.end(), [](const Foo& i, const Foo& j) -> bool { return i.myValue < j.myValue; });
An alternative, non-lambda version would be:
struct myclass {
bool operator() (const Foo& i, const Foo& j) { return (i.myValue < j.myValue); }
} myobject;
std::sort(myVector.begin(), myVector.end(), myobject);
And here's how you would do the same sort using boost's operator overload:
std::sort(myVector.begin(), myVector.end(), boost::bind(&MyClass::myValue, _1) < boost::bind(&MyClass::myValue, _2))

I think it is because C++11 has lambda, and therefore I don't see why you would need such operators instead.

Related

std::set of MyElement with MyElement::SomeMethod as custom comparator

I have a simple MyElement class, and I would like to use a bool MyElement::SomeMethod(...) {...} as the custom comparator for a std::set of MyElement items.
I have made my research, and I am already aware of some alternative solutions, which I list below.
I also know how to change, for example, the comparator with std::greater instead of the default std::less, with code like this:
std::set<MyElement, std::greater<MyElement> > s;
My exact problem is that I want to use bool MyElement::SomeMethod(...) {...} as custom comparator.
The only solution I come up with is analogous to the last one in the list below, namely the solution for boolean function:
using Cmp = std::integral_constant<decltype(&MyElement::SomeMethod),
&MyElement::SomeMethod>;
std::set<MyElement, Cmp> my_set;
This solution only works for a static MyElement::SomeMethod, though.
I am wondering if there is an analgous, or more concise, way for a non static method.
List of alternative solutions:
method for C++20
auto cmp = [](const MyElement& lhs, const MyElement& rhs) { return ... };
std::set<MyElement, decltype(cmp)> s;
method for C++11
auto cmp = [](const MyElement& lhs, const MyElement& rhs) { return ... };
std::set<MyElement, decltype(cmp)> s(cmp);
function instead of a lambda
bool cmp(const MyElement& lhs, const MyElement& rhs) { return ...; }
and then
std::set<MyElement, decltype(cmp)*> s(cmp);
or
std::set<int, decltype(&cmp)> s(&cmp);
struct and operator()
struct cmp {
bool operator() (const MyElement& lhs, const MyElement& rhs) const {
return ...
}
};
and then
std::set<MyElement, cmp> s;
boolean function
bool cmp(const MyElement& lhs, const MyElement& rhs) {
return ...;
}
and then
#include <type_traits>
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;
std::set<MyElement, Cmp> s;
This is a bit subjective, but to me the cleanest option is struct + operator() to match the definition of std::less, the default comparator for std::set. There's nothing wrong with the other options but a comparison functor is a common pattern and easy to recognize.
You could also define MyElement::operator<, and then you wouldn't need to pass in a comparator separately.
You can use std::mem_fn to bind a member function.
#include <functional>
#include <iostream>
#include <set>
#include <utility>
struct S {
int i;
bool cmp(const S& other) const { return i < other.i; }
};
// Define make function to avoid having to write out template types.
template <typename T, typename Cmp>
std::set<T, Cmp> make_set(Cmp&& cmp) {
return std::set<T, Cmp>{std::forward<Cmp>(cmp)};
}
int main(int argc, char* argv[]) {
auto s = make_set<S>(std::mem_fn(&S::cmp));
s.emplace(S{0});
std::cout << s.begin()->i << std::endl;
return 0;
}

a generic builder to create a comparator for arbitrary objects, which can take a arbitrary data member in the object to sort

I need to write a comparator builder which can generate a comparator for std:sort. This builder can deal with any generic objects, and take an arbitrary data member of the object in std:vector to sort. so we need to pass in the class data member pointer to comparator_builder's constructor. The usage and the interface of this comparator_builder is shown below:
vector<T> arr;
sort( arr.begin(), arr.end(), comparator_builder( &T::data_memeber ) );
Since we don't know what objects to be sorted is before-hand, we can't know what data member will be in it. We need to also make the class member pointer generic. No idea how to implement it using template. Is there any C++ expert or genius who can give me some guidance?
The following is my code. But they can't be complied even.
template <typename ObjectType, typename MemberType >
class Comparator {
public:
Comparator ( ObjectType::data_address ) {
data_ptr = &data_address
}
bool operator()( ObjectType x, ObjectType y ) {
return x.*data_ptr < y.*data_ptr;
}
MemberType ObjectType::* data_ptr;
};
template <typename ObjectType, typename MemberType >
class Comparator_Builder{
ObjectType::member_address ;
public:
Comparator_Builder( ObjectType::mem_address ) {
member_address = mem_address;
}
Comparator < ObjectType, MemberType ObjectType::* > operator()() {
return Comparator < ObjectType, MemberType ObjectType::* >( member_address );
}
};
You're already most of the way there with your comparator class:
template <typename ObjectType, typename MemberType>
class MemberComparator {
public:
using MemberPtr = MemberType ObjectType::*;
explicit MemberComparator(MemberPtr ptr) : m_ptr(ptr) {}
bool operator()(const ObjectType& x, const ObjectType& y) const {
return x.*m_ptr < y.*m_ptr;
}
private:
MemberPtr m_ptr;
};
Just a few syntax fixes and that's all you need. Constructor template argument deduction also makes this really easy to use in C++17:
std::sort(vec.begin(), vec.end(), MemberComparator(&T::data_member));
If you don't have C++17 you either have to manually specify the template parameters or you can create a template function to do the deduction:
template <typename ObjectType, typename MemberType>
auto GetComparator(MemberType ObjectType::*ptr) {
return MemberComparator<ObjectType, MemberType>(ptr);
}
And then use it like this:
std::sort(vec.begin(), vec.end(), GetComparator(&T::data_member));
From the comments:
is it possible that we make argument passed into GetComparator() more generic? so that we can also pass in getter function, which is class function pointer, like this std::sort(vec.begin(), vec.end(), GetComparator(&T:: get_data_member) );?
Yes, we could certainly add implementations for member functions, though you'll start to run into problems if those getters are overloaded. This can be made more generic, however:
template <typename F>
auto GetComparator(F&& func) {
return [f = std::forward<F>(func)](auto&& lhs, auto&& rhs) {
return f(lhs) < f(rhs);
};
}
Now we can do this:
std::sort(vec.begin(), vec.end(), [](const auto &value) { return value.get_data_member(); });
This can likewise replace the member pointer comparator we have above by just doing e.g.:
std::sort(vec.begin(), vec.end(), [](const auto &value) { return value.data_member; });
If you like the member pointer syntax we can add overloads for that and even replace the MemberComparator class entirely:
template <typename ObjectType, typename MemberType>
auto GetComparator(MemberType ObjectType::*ptr) {
return [ptr](const ObjectType& lhs, const ObjectType& rhs) {
return lhs.*ptr < rhs.*ptr;
};
}
template <typename ObjectType, typename MemberType>
auto GetComparator(MemberType (ObjectType::*ptr)()) {
return [ptr](ObjectType& lhs, ObjectType& rhs) {
return (lhs.*ptr)() < (rhs.*ptr)();
};
}
template <typename ObjectType, typename MemberType>
auto GetComparator(MemberType (ObjectType::*ptr)() const) {
return [ptr](const ObjectType& lhs, const ObjectType& rhs) {
return (lhs.*ptr)() < (rhs.*ptr)();
};
}

Comparator for sort, specialization

In a template function a std::vector shall get sorted. T can be a simple type or a std::pair e.g.,
std::vector<double> or
std::vector<std::pair<int,Something> >
When T is a pair then only the first element shall be compared. How can I implement the comparator for the two cases?
I have tried:
template<typename T>
inline bool smaller(const T& a,const T& b)
{
return a<b;
}
template<typename T,typename S>
inline bool smaller(
const std::pair<T,S>& a,
const std::pair<T,S>& b
)
{
return a.first<b.first;
}
template<typename T> inline void function(std::vector<T >& vVec)
{
...bla...
sort(vVec.begin(),vVec.end(),smaller<T>);
...bla...
}
but it does not work this way. I have also tried specialization but I do not find the right syntax to specialize the smaller() function.
You could just wrap it in a lambda:
std::sort(vVec.begin(),vVec.end(), [](const auto& a, const auto& b) { return smaller(a, b); });
One easy work around is to make both of your smaller functions opeator()'s of a smaller struct. Using
struct smaller
{
template<typename T>
bool operator()(const T& a,const T& b)
{
return a < b;
}
template<typename T, typename S>
bool operator() (const std::pair<T, S>& a, const std::pair<T, S>& b)
{
return a.first < b.first;
}
};
allows you to just pass a smaller to sort like
template<typename T> inline void function(std::vector<T >& vVec)
{
sort(vVec.begin(),vVec.end(),smaller{});
}
and in sort overload resolution will kick in on the two operator() smaller has and for any std::vector<std::pair>, the std::pair overload will be called.

Sorting a pair of vectors

I know how to sort a vector of pairs, but how do you sort a pair of vectors? I can think of writing a custom "virtual" iterator over a pair of vectors and sorting that, but that seems quite complex. Is there an easier way? Is there one in C++03? I would like to use std::sort.
This problem arises when processing some data generated in hardware, where a pair of arrays makes more sense than array of pairs (since then there would be all kinds of stride and alignment problems). I realize that otherwise keeping a pair of vector instead of a vector of pairs would be a design flaw (the structure of arrays problem). I'm looking for a fast solution, copying the data to a vector of pairs and then back (I will return it to the HW to do more processing) is not an option.
Example:
keys = {5, 2, 3, 1, 4}
values = {a, b, d, e, c}
and after sorting (by the first vector):
keys = {1, 2, 3, 4, 5}
values = {e, b, d, c, a}
I refer to a "pair of vectors" as the pair of keys and values (stored as e.g. std::pair<std::vector<size_t>, std::vector<double> >). The vectors have the same length.
Let's make a sort/permute iterator, so that we can just say:
int keys[] = { 5, 2, 3, 1, 4 };
char vals[] = { 'a', 'b', 'd', 'e', 'c' };
std::sort(make_dual_iter(begin(keys), begin(vals)),
make_dual_iter(end(keys), end(vals)));
// output
std::copy(begin(keys), end(keys), std::ostream_iterator<int> (std::cout << "\nKeys:\t", "\t"));
std::copy(begin(vals), end(vals), std::ostream_iterator<char>(std::cout << "\nValues:\t", "\t"));
See it Live On Coliru, printing
Keys: 1 2 3 4 5
Values: e b d c a
Based on the idea here, I've implemented this:
namespace detail {
template <class KI, class VI> struct helper {
using value_type = boost::tuple<typename std::iterator_traits<KI>::value_type, typename std::iterator_traits<VI>::value_type>;
using ref_type = boost::tuple<typename std::iterator_traits<KI>::reference, typename std::iterator_traits<VI>::reference>;
using difference_type = typename std::iterator_traits<KI>::difference_type;
};
}
template <typename KI, typename VI, typename H = typename detail::helper<KI, VI> >
class dual_iter : public boost::iterator_facade<dual_iter<KI, VI>, // CRTP
typename H::value_type, std::random_access_iterator_tag, typename H::ref_type, typename H::difference_type>
{
public:
dual_iter() = default;
dual_iter(KI ki, VI vi) : _ki(ki), _vi(vi) { }
KI _ki;
VI _vi;
private:
friend class boost::iterator_core_access;
void increment() { ++_ki; ++_vi; }
void decrement() { --_ki; --_vi; }
bool equal(dual_iter const& other) const { return (_ki == other._ki); }
typename detail::helper<KI, VI>::ref_type dereference() const {
return (typename detail::helper<KI, VI>::ref_type(*_ki, *_vi));
}
void advance(typename H::difference_type n) { _ki += n; _vi += n; }
typename H::difference_type distance_to(dual_iter const& other) const { return ( other._ki - _ki); }
};
Now the factory function is simply:
template <class KI, class VI>
dual_iter<KI, VI> make_dual_iter(KI ki, VI vi) { return {ki, vi}; }
Note I've been a little lazy by using boost/tuples/tuple_comparison.hpp for the sorting. This could pose a problem with stable sort when multiple key values share the same value. However, in this case it's hard to define what is "stable" sort anyways, so I didn't think it important for now.
FULL LISTING
Live On Coliru
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/tuple/tuple_comparison.hpp>
namespace boost { namespace tuples {
// MSVC might not require this
template <typename T, typename U>
inline void swap(boost::tuple<T&, U&> a, boost::tuple<T&, U&> b) noexcept {
using std::swap;
swap(boost::get<0>(a), boost::get<0>(b));
swap(boost::get<1>(a), boost::get<1>(b));
}
} }
namespace detail {
template <class KI, class VI> struct helper {
using value_type = boost::tuple<typename std::iterator_traits<KI>::value_type, typename std::iterator_traits<VI>::value_type>;
using ref_type = boost::tuple<typename std::iterator_traits<KI>::reference, typename std::iterator_traits<VI>::reference>;
using difference_type = typename std::iterator_traits<KI>::difference_type;
};
}
template <typename KI, typename VI, typename H = typename detail::helper<KI, VI> >
class dual_iter : public boost::iterator_facade<dual_iter<KI, VI>, // CRTP
typename H::value_type, std::random_access_iterator_tag, typename H::ref_type, typename H::difference_type>
{
public:
dual_iter() = default;
dual_iter(KI ki, VI vi) : _ki(ki), _vi(vi) { }
KI _ki;
VI _vi;
private:
friend class boost::iterator_core_access;
void increment() { ++_ki; ++_vi; }
void decrement() { --_ki; --_vi; }
bool equal(dual_iter const& other) const { return (_ki == other._ki); }
typename detail::helper<KI, VI>::ref_type dereference() const {
return (typename detail::helper<KI, VI>::ref_type(*_ki, *_vi));
}
void advance(typename H::difference_type n) { _ki += n; _vi += n; }
typename H::difference_type distance_to(dual_iter const& other) const { return ( other._ki - _ki); }
};
template <class KI, class VI>
dual_iter<KI, VI> make_dual_iter(KI ki, VI vi) { return {ki, vi}; }
#include <iostream>
using std::begin;
using std::end;
int main()
{
int keys[] = { 5, 2, 3, 1, 4 };
char vals[] = { 'a', 'b', 'd', 'e', 'c' };
std::sort(make_dual_iter(begin(keys), begin(vals)),
make_dual_iter(end(keys), end(vals)));
std::copy(begin(keys), end(keys), std::ostream_iterator<int> (std::cout << "\nKeys:\t", "\t"));
std::copy(begin(vals), end(vals), std::ostream_iterator<char>(std::cout << "\nValues:\t", "\t"));
}
Just for comparison, this is how much code the split iterator approach requires:
template <class V0, class V1>
class CRefPair { // overrides copy semantics of std::pair
protected:
V0 &m_v0;
V1 &m_v1;
public:
CRefPair(V0 &v0, V1 &v1)
:m_v0(v0), m_v1(v1)
{}
void swap(CRefPair &other)
{
std::swap(m_v0, other.m_v0);
std::swap(m_v1, other.m_v1);
}
operator std::pair<V0, V1>() const // both g++ and msvc sort requires this (to get a pivot)
{
return std::pair<V0, V1>(m_v0, m_v1);
}
CRefPair &operator =(std::pair<V0, V1> v) // both g++ and msvc sort requires this (for insertion sort)
{
m_v0 = v.first;
m_v1 = v.second;
return *this;
}
CRefPair &operator =(const CRefPair &other) // required by g++ (for _GLIBCXX_MOVE)
{
m_v0 = other.m_v0;
m_v1 = other.m_v1;
return *this;
}
};
template <class V0, class V1>
inline bool operator <(std::pair<V0, V1> a, CRefPair<V0, V1> b) // required by both g++ and msvc
{
return a < std::pair<V0, V1>(b); // default pairwise lexicographical comparison
}
template <class V0, class V1>
inline bool operator <(CRefPair<V0, V1> a, std::pair<V0, V1> b) // required by both g++ and msvc
{
return std::pair<V0, V1>(a) < b; // default pairwise lexicographical comparison
}
template <class V0, class V1>
inline bool operator <(CRefPair<V0, V1> a, CRefPair<V0, V1> b) // required by both g++ and msvc
{
return std::pair<V0, V1>(a) < std::pair<V0, V1>(b); // default pairwise lexicographical comparison
}
namespace std {
template <class V0, class V1>
inline void swap(CRefPair<V0, V1> &a, CRefPair<V0, V1> &b)
{
a.swap(b);
}
} // ~std
template <class It0, class It1>
class CPairIterator : public std::random_access_iterator_tag {
public:
typedef typename std::iterator_traits<It0>::value_type value_type0;
typedef typename std::iterator_traits<It1>::value_type value_type1;
typedef std::pair<value_type0, value_type1> value_type;
typedef typename std::iterator_traits<It0>::difference_type difference_type;
typedef /*typename std::iterator_traits<It0>::distance_type*/difference_type distance_type; // no distance_type in g++, only in msvc
typedef typename std::iterator_traits<It0>::iterator_category iterator_category;
typedef CRefPair<value_type0, value_type1> reference;
typedef reference *pointer; // not so sure about this, probably can't be implemented in a meaningful way, won't be able to overload ->
// keep the iterator traits happy
protected:
It0 m_it0;
It1 m_it1;
public:
CPairIterator(const CPairIterator &r_other)
:m_it0(r_other.m_it0), m_it1(r_other.m_it1)
{}
CPairIterator(It0 it0 = It0(), It1 it1 = It1())
:m_it0(it0), m_it1(it1)
{}
reference operator *()
{
return reference(*m_it0, *m_it1);
}
value_type operator *() const
{
return value_type(*m_it0, *m_it1);
}
difference_type operator -(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
// the iterators always need to have the same position
// (incomplete check but the best we can do without having also begin / end in either vector)
return m_it0 - other.m_it0;
}
bool operator ==(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
return m_it0 == other.m_it0;
}
bool operator !=(const CPairIterator &other) const
{
return !(*this == other);
}
bool operator <(const CPairIterator &other) const
{
assert(m_it0 - other.m_it0 == m_it1 - other.m_it1);
return m_it0 < other.m_it0;
}
bool operator >=(const CPairIterator &other) const
{
return !(*this < other);
}
bool operator <=(const CPairIterator &other) const
{
return !(other < *this);
}
bool operator >(const CPairIterator &other) const
{
return other < *this;
}
CPairIterator operator +(distance_type d) const
{
return CPairIterator(m_it0 + d, m_it1 + d);
}
CPairIterator operator -(distance_type d) const
{
return *this + -d;
}
CPairIterator &operator +=(distance_type d)
{
return *this = *this + d;
}
CPairIterator &operator -=(distance_type d)
{
return *this = *this + -d;
}
CPairIterator &operator ++()
{
return *this += 1;
}
CPairIterator &operator --()
{
return *this += -1;
}
CPairIterator operator ++(int) // msvc sort actually needs this, g++ does not
{
CPairIterator old = *this;
++ (*this);
return old;
}
CPairIterator operator --(int)
{
CPairIterator old = *this;
-- (*this);
return old;
}
};
template <class It0, class It1>
inline CPairIterator<It0, It1> make_pair_iterator(It0 it0, It1 it1)
{
return CPairIterator<It0, It1>(it0, it1);
}
It is kind of rough around the edges, maybe I'm just bad at overloading the comparisons, but the amount of differences needed to support different implementations of std::sort makes me think the hackish solution might actually be more portable. But the sorting is much nicer:
struct CompareByFirst {
bool operator ()(std::pair<size_t, char> a, std::pair<size_t, char> b) const
{
return a.first < b.first;
}
};
std::vector<char> vv; // filled by values
std::vector<size_t> kv; // filled by keys
std::sort(make_pair_iterator(kv.begin(), vv.begin()),
make_pair_iterator(kv.end(), vv.end()), CompareByFirst());
// nice
And of course it gives the correct result.
Inspired by a comment by Mark Ransom, this is a horrible hack, and an example of how not to do it. I only wrote it for amusement and because I was wondering how complicated would it get. This is not an answer to my question, I will not use this. I just wanted to share a bizarre idea. Please, do not downvote.
Actually, ignoring multithreading, I believe this could be done:
template <class KeyType, class ValueVectorType>
struct MyKeyWrapper { // all is public to save getters
KeyType k;
bool operator <(const MyKeyWrapper &other) const { return k < other.k; }
};
template <class KeyType, class ValueVectorType>
struct ValueVectorSingleton { // all is public to save getters, but kv and vv should be only accessible by getters
static std::vector<MyKeyWrapper<KeyType, ValueVectorType> > *kv;
static ValueVectorType *vv;
static void StartSort(std::vector<MyKeyWrapper<KeyType, ValueVectorType> > &_kv, ValueVectorType &_vv)
{
assert(!kv && !vv); // can't sort two at once (if multithreading)
assert(_kv.size() == _vv.size());
kv = &_kv, vv = &_vv; // not an attempt of an atomic operation
}
static void EndSort()
{
kv = 0, vv = 0; // not an attempt of an atomic operation
}
};
template <class KeyType, class ValueVectorType>
std::vector<MyKeyWrapper<KeyType, ValueVectorType> >
*ValueVectorSingleton<KeyType, ValueVectorType>::kv = 0;
template <class KeyType, class ValueVectorType>
ValueVectorType *ValueVectorSingleton<KeyType, ValueVectorType>::vv = 0;
namespace std {
template <class KeyType, class ValueVectorType>
void swap(MyKeyWrapper<KeyType, ValueVectorType> &a,
MyKeyWrapper<KeyType, ValueVectorType> &b)
{
assert((ValueVectorSingleton<KeyType, ValueVectorType>::vv &&
ValueVectorSingleton<KeyType, ValueVectorType>::kv)); // if this triggers, someone forgot to call StartSort()
ValueVectorType &vv = *ValueVectorSingleton<KeyType, ValueVectorType>::vv;
std::vector<MyKeyWrapper<KeyType, ValueVectorType> > &kv =
*ValueVectorSingleton<KeyType, ValueVectorType>::kv;
size_t ai = &kv.front() - &a, bi = &kv.front() - &b; // get indices in key vector
std::swap(a, b); // swap keys
std::swap(vv[ai], vv[bi]); // and any associated values
}
} // ~std
And sorting as:
std::vector<char> vv; // filled by values
std::vector<MyKeyWrapper<size_t, std::vector<char> > > kv; // filled by keys, casted to MyKeyWrapper
ValueVectorSingleton<size_t, std::vector<char> >::StartSort(kv, vv);
std::sort(kv.begin(), kv.end());
ValueVectorSingleton<size_t, std::vector<char> >::EndSort();
// trick std::sort into using the custom std::swap which also swaps the other vectors
This is obviously very appalling, trivial to abuse in horrible ways, but arguably much shorter than the pair of iterators and probably similar in performance. And it actually works.
Note that swap() could be implemented inside ValueVectorSingleton and the one injected in the std namespace would just call it. That would avoid having to make vv and kv public. Also, the addresses of a and b could further be checked to make sure they are inside kv and not some other vector. Also, this is limited to sorting by values of only one vector (can't sort by corresponding values in both vectors at the same time). And the template parameters could be simply KeyType and ValueType, this was written in a hurry.
Here is a solution I once used to sort an array together with an array of indices (--maybe it is from somewhere over here?):
template <class iterator>
class IndexComparison
{
public:
IndexComparison (iterator const& _begin, iterator const& _end) :
begin (_begin),
end (_end)
{}
bool operator()(size_t a, size_t b) const
{
return *std::next(begin,a) < *std::next(begin,b);
}
private:
const iterator begin;
const iterator end;
};
Usage:
std::vector<int> values{5,2,5,1,9};
std::vector<size_t> indices(values.size());
std::iota(indices.begin(),indices.end(),0);
std::sort(indices.begin(),indices.end()
, IndexComparison<decltype(values.cbegin())>(values.cbegin(),values.cend()));
Afterwards, the integers in vector indices are permuted such that they correspond to increasing values in the vector values. It is easy to extend this from less-comparison to general comparison functions.
Next, in order to sort also the values, you can do another
std::sort(values.begin(),values.end());
using the same comparison function. This is the solution for the lazy ones. Of course, you can alternatively also use the sorted indices according to
auto temp=values;
for(size_t i=0;i<indices.size();++i)
{
values[i]=temp[indices[i]];
}
DEMO
EDIT: I just realized that the above sorts into the opposite direction than the one you were asking for.

C++ equivalent to Python's cmp or Haskell's compare

Question:
Is there a C++ equivalent for Python's cmp or Haskell's compare?
compare is like operator== and operator< in one. It returns LT, EQ, or GT. But it's twice as fast as calling both operator== and operator< because it does it in one pass.
More details:
At work, I often have structs that are used as keys for maps, for example:
struct RecordUsedAsAKey {
int field_a;
string field_b;
vector<float> field_c;
// operator< is needed for keys in maps.
bool operator<(const RecordUsedAsAKey& other) const;
};
bool RecordUsedAsAKey::operator<(const RecordUsedAsAKey& other) const {
if (field_a != other.field_a)
return field_a < other.field_a;
if (field_b != other.field_b)
return field_b < other.field_b;
return field_c < other.field_c;
}
One problem with RecordUsedAsAKey::operator< is that it's unnecessarily slow.
When the string::operator!= finds a different character, the program iterates over the equal characters again in the string::operator<, when it could have skipped those..
Same for the vector's comparison.
If I had an equivalent to Haskell's compare, my comparison method would had been more efficient:
Ordering RecordUsedAsAKey::compare(const RecordUsedAsAKey& other) const {
Ordering t;
if ((t = field_a.compare(other.field_a)) != EQ)
return t;
if ((t = field_b.compare(other.field_b)) != EQ)
return t;
return field_c.compare(other.field_c);
}
This is more efficient because the string's compare method does only one pass on the string.
Btw/mini-flame-war: in Haskell the whole code for the comparison would just be deriving Ord.
You can easily implement it yourself, as a free function.
#include <string>
#include <vector>
enum order {
order_lt = -1,
order_eq,
order_gt
};
// General case, templated version.
template < typename T >
order compare(T left, T right) {
if (left < right)
return order_lt;
if (left == right)
return order_eq;
return order_gt;
}
// Specialization
order compare(const std::string& left, const std::string& right) {
return order(left.compare(right));
}
template < typename T >
order compare(const std::vector<T>& left, const std::vector<T>& right) {
order o = compare(left.size(), right.size());
if (o != order_eq)
return o;
for (size_t i = 0; i < left.size(); ++ i) {
o = compare(left[i], right[i]);
if (o != order_eq)
return o;
}
return order_eq;
}
Note: I edited the code to include a templated version for the general case (work provided that the operator< and operator== are defined for the type). I also kept some specialization as it can improve run time on some type (mainly containers).
Edit: Using std::string::compare instead of strcmp.
Since map semantics are in term of operator<, and that in fact many operators implementations are in term of operator<, probably something only in term of it is better.
For instance:
template <typename T>
int compare(const T& x, const T& y)
{
if (x < y) return -1;
else if (y < x) return 1;
else return 0;
}
or, better,
template <typename T, typename F>
int compare(const T& x, const T& y, F pred)
{
if (pred(x, y)) return -1;
else if (pred(y, x)) return 1;
else return 0;
}
template <typename T>
int compare(const T& x, const T& y)
{
return compare(x, y, std::less<T>());
}
so that you can use compare(k1, k2, mymap.key_comp()) if you need to.
After your program works, and you are convinced that compare is the bottleneck, you can specialize for the offending types. Do for instance
template <typename C, typename T, typename A>
int compare(const std::basic_string<C, T, A>& x,
const std::basic_string<C, T, A>& y)
{
return x.compare(y);
}
if you are worried about efficiency for string types.
If you are comparing sequences, you can use std::lexicographical_compare. However, you may want to reimplement it to handle the equality case, here is an optimized version for std::vector:
template <typename T, typename A, typename F>
int compare(const std::vector<T, A>& x,
const std::vector<T, A>& y, F pred)
{
std::vector<T, A>::const_iterator i = x.begin();
std::vector<T, A>::const_iterator j = y.begin();
while (i != x.end())
{
if (j == y.end()) return 1;
if (pred(*i, *j)) return -1
else if (pred(*j, *i)) return 1;
++i; ++j;
}
return j == y.end() ? 0 : -1;
}
simpler and more general version of Sylvain Defresne's answer:
template<typename T>
order compare(const T &left, const T &right) {
if (left < right)
return order_lt;
else if (left == right)
return order_eq;
return order_gt;
}
The std::string already has a compare member function that does what you want.
For other sequences, like std::vector, there is a std::mismatch function in <algorithm> that scans two sequences side-by-side and returns iterators to the first two elements that differ. From there, you only have to figure out if these two elements are less than or greater than each other.