I have a vector of pairs that I want to be stable sorted only by the key (which may occur multiple times). I do not use a multimap for this, because it is not explicitly stable. Therefore, I supply a custom compare function to stable_sort. I'm struggling now with templatizing this function. A brief test implementation follows to show you the use case:
#include <iostream>
#include <algorithm>
#include <vector>
#include "test.h"
using namespace std;
int main() {
typedef pair<int, int> TPair;
vector<TPair> data(10);
data[0] = make_pair(7, 1);
data[1] = make_pair(3, 2);
data[2] = make_pair(8, 0);
data[3] = make_pair(5, 1);
data[4] = make_pair(3, 1);
data[5] = make_pair(2, 0);
data[6] = make_pair(7, 0);
data[7] = make_pair(6, 0);
data[8] = make_pair(5, 0);
data[9] = make_pair(3, 0);
stable_sort(data.begin(), data.end(), comp1);
for (unsigned int i = 0; i < 10; ++i) {
cout << data[i].first << "\t" << data[i].second << endl;
}
return 0;
}
The supplied sorting function is available in test.h:
#include <vector>
#ifndef TEST_H_
#define TEST_H_
using namespace std;
bool comp1(pair<int, int> const & a, pair<int, int> const & b) {
return a.first < b.first;
}
template <typename TElemA, typename TElemB>
bool comp2(pair<TElemA, TElemB> const & a, pair<TElemA, TElemB> const & b) {
return a.first < b.first;
}
template <typename TPair>
bool comp3(TPair const & a, TPair const & b) {
return a.first < b.first;
}
#endif
comp1 works well, nothing to complain. First I tried to templatize the elements of the pairs:
comp2 doesn't work: test.cpp:25:3: error: no matching function for call to 'stable_sort'.
comp3 fails with the same error message as comp2.
What is wrong with this template function?
stable_sort is itself a template, the type of its third parameter is a template parameter. This means that you cannot pass a function template as the argument, because template argument deduction cannot apply here - there's nothing to tell which instantiation you'd be after. So you'd have to specify the template argument explicitly:
stable_sort(data.begin(), data.end(), comp2<int, int>);
However, you'll be better off if you provide a functor for that:
struct comp2
{
template <typename TElemA, typename TElemB>
bool operator() (pair<TElemA, TElemB> const & a, pair<TElemA, TElemB> const & b) const {
return a.first < b.first;
}
};
stable_sort(data.begin(), data.end(), comp2());
That way, the actual template argument deduction is postponed until the time when the desired types are known.
Since C++14, you can also use a lambda expression instead of using a template. This is, because C++14 allows for generic lambdas, whose function parameters can be declared with the auto type specifier:
std::stable_sort(std::begin(data), std::end(data), [](auto const &a, auto const &b){
return a.first < b.first;
});
This way your code becomes rather short, but still works for any comparable std::pair key.
Code on Ideone
Related
I have the following situation: I must pack several pointers and an identifier into a tuple like this:
typedef tuple<unsigned*, unsigned*, unsigned*, unsigned> tuple_with_pointers_t;
Here, I have three pointers and one id. In other situations, I may have more or fewer pointers, but the last will be the id. Note that I used unsigned* as an example only. It could be more complex objects.
Now, I want to compare the values of two such tuples. I.e., I need to dereference all tuple elements but the last. We can archive this using the following (in C++17):
template <size_t I = 0, typename T, typename... Ts>
constexpr bool lesser(std::tuple<T, Ts...> a, std::tuple<T, Ts...> b)
{
if constexpr (I < sizeof...(Ts))
return (*std::get<I>(a) < *std::get<I>(b)) ||
((*std::get<I>(a) == *std::get<I>(b)) && lesser<I + 1>(a, b));
else
return std::get<I>(a) < std::get<I>(b);
}
Such construct works very fine when we compare two tuples directly. Now, I would like to use lesser() as a functor on the std::sort(). But, both g++ and clang++ complain that they cannot "couldn't infer template argument '_Compare'". In other words, we need to pass the correct template arguments to lesser.
I have tried some things here, but with no success: we have three template parameters, and I am not sure how I can use the _Elements from the tuple here. What will be the best strategy?
Here is some toy code:
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
// My weird tuple with pointers and one unsigned index.
typedef tuple<unsigned*, unsigned*, unsigned*, unsigned> tuple_with_pointers_t;
// This works fine for two tuples directly. Note that we cannot dereference
// the last tuple element, so we compare it directly.
template <size_t I = 0, typename T, typename... Ts>
constexpr bool lesser(std::tuple<T, Ts...> a, std::tuple<T, Ts...> b)
{
if constexpr (I < sizeof...(Ts))
return (*std::get<I>(a) < *std::get<I>(b)) ||
((*std::get<I>(a) == *std::get<I>(b)) && lesser<I + 1>(a, b));
else
return std::get<I>(a) < std::get<I>(b);
}
int main() {
// Three sets of values.
vector<unsigned> values1 {1, 2, 3};
vector<unsigned> values2 {10, 20, 30};
vector<unsigned> values3 {11, 22, 33};
// Here, we pack it all together with the index.
vector<tuple_with_pointers_t> all;
for(unsigned i = 0; i < values1.size(); ++i)
all.emplace_back(&values1[i], &values2[i], &values3[i], i);
// So, it works if we want to compare two elements of our vector.
cout << "\n- t0 < t1: " << std::boolalpha << lesser(all[0], all[1]);
cout << "\n- t2 < t1: " << std::boolalpha << lesser(all[2], all[1]);
// Now, I want to sort the tuples by their values. The compiler doesn't
// like it: it cannot deduce the template parameters.
sort(all.begin(), all.end(), lesser);
return 0;
}
I appreciate any help, either using C++17 or C++20. But I'm looking for the most compact and elegant way to do it. It could be using a lambda function directly on the sort() call, too, if possible.
Thanks!
Update:
OK, I found a little hack that works:
sort(all.begin(), all.end(),
[](const auto &a, const auto &b) {
return lesser(a, b);
}
);
Basically, we wrap it into a lambda, and therefore the compiler can deduce the types. But, can we do better?
Thanks
As suggested in the comments, you can add your comparator into a function object and pass an instance of the object to sort:
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
// My weird tuple with pointers and one unsigned index.
typedef tuple<unsigned*, unsigned*, unsigned*, unsigned> tuple_with_pointers_t;
namespace details {
template <size_t I = 0, typename T, typename... Ts>
constexpr bool lesser(std::tuple<T, Ts...> const& a, std::tuple<T, Ts...> const& b)
{
if constexpr (I < sizeof...(Ts))
return (*std::get<I>(a) < *std::get<I>(b)) ||
((*std::get<I>(a) == *std::get<I>(b)) && lesser<I + 1>(a, b));
else
return std::get<I>(a) < std::get<I>(b);
}
}
struct Less
{
template <typename... Ts>
constexpr bool operator()(std::tuple<Ts...> const& a, std::tuple<Ts...> const& b)
{
return details::lesser<0, Ts...>(a, b);
}
};
int main() {
// Three sets of values.
vector<unsigned> values1 {1, 2, 3};
vector<unsigned> values2 {10, 20, 30};
vector<unsigned> values3 {11, 22, 33};
// Here, we pack it all together with the index.
vector<tuple_with_pointers_t> all;
for(unsigned i = 0; i < values1.size(); ++i)
all.emplace_back(&values1[i], &values2[i], &values3[i], i);
// So, it works if we want to compare two elements of our vector.
cout << "\n- t0 < t1: " << std::boolalpha << Less()(all[0], all[1]);
cout << "\n- t2 < t1: " << std::boolalpha << Less()(all[2], all[1]);
// Now, I want to sort the tuples by their values. The compiler doesn't
// like it: it cannot deduce the template parameters.
sort(all.begin(), all.end(), Less());
return 0;
}
As an alternative, you could wrap your unsigned* in a custom pointer type and provide a comparator for it. Then you can use the default comperator for tuples, which compares the elements lexicographically.
I personally would prefer this approach, because the code is much more readable. I don't know if this would break your existing code or would entail a huge refactor.
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
class Ptr
{
public:
Ptr(unsigned& v) : m_ptr(&v) {}
unsigned operator*() const {
return *m_ptr;
}
private:
unsigned* m_ptr;
};
bool operator<(Ptr const& l, Ptr const& r)
{
return *l < *r;
}
// My weird tuple with pointers and one unsigned index.
typedef tuple<Ptr, Ptr, Ptr, unsigned> tuple_with_pointers_t;
int main() {
// Three sets of values.
vector<unsigned> values1 {1, 2, 3};
vector<unsigned> values2 {10, 20, 30};
vector<unsigned> values3 {11, 22, 33};
// Here, we pack it all together with the index.
vector<tuple_with_pointers_t> all;
for(unsigned i = 0; i < values1.size(); ++i)
all.emplace_back(values1[i], values2[i], values3[i], i);
// So, it works if we want to compare two elements of our vector.
cout << "\n- t0 < t1: " << std::boolalpha << (all[0] < all[1]);
cout << "\n- t2 < t1: " << std::boolalpha << (all[2] < all[1]);
sort(all.begin(), all.end());
return 0;
}
I think we can use this. Of course, I don't know your tuple can be more complex.
template<typename T, size_t I = 0>
using type_tuple = typename std::tuple_element<I,T>::type;
template<size_t I = 0, template<typename> class F = std::less_equal>
struct TupleCompare
{
template<typename T>
bool operator()(T const &t1, T const &t2){
using _type = typename std::conditional<std::is_pointer<type_tuple<T>>::value,
typename std::remove_pointer<type_tuple<T,I>>::type, type_tuple<T>>::type;
if constexpr (I == std::tuple_size_v<T> - 1) {
return F<_type>()(std::get<I>(t1), std::get<I>(t2));
} else {
return F<_type>()(*std::get<I>(t1), *std::get<I>(t2)) && TupleCompare<I+1, F>()(t1, t2);
}
}
};
By doing a non-"recursive" function, you might do a "one-liner":
sort(all.begin(), all.end(),
[]<typename T>(const T& lhs, const T& rhs) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
return std::tie(std::get<Is>(lhs)...)
< std::tie(std::get<Is>(rhs)...);
}(std::make_index_sequence<std::tuple_size_v<T> - 1>{});
});
template lambda are C++20.
Without that, at least an helper function is required, so it becomes, as the other solutions, wrapping a function in a functor.
I've check the prototype of std::sort and std::priority_queue, the custom Compare type defined in the template looks quite the same.
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
But actually they differ, std::sort accepts a function predicate, while std::priority_queue accepts a struct(a type). Why? Thanks in advance!.
struct cmp {
bool operator() (const int &a, const int &b) {
return a < b;
}
};
vector<int> v;
v.push_back(2);
v.push_back(3);
v.push_back(1);
// this works
sort(v.begin(), v.end(), [](const int &a, const int &b) -> bool {
return a < b;
});
// this not works
// sort(v.begin(), v.end(), cmp);
cout << v[0] << endl;
// this works
priority_queue<int, cmp> q;
// this not works
// priority_queue<int, [](const int &a, const int &b) -> bool {
// return a < b;
// }> q;
q.push(2);
q.push(3);
q.push(1);
cout << q.top() << endl;
The difference is that sort is a function template and thus the template argument for Comparator can be deduced from the type of the function argument. When you call it like this:
sort(v.begin(), v.end(), [](const int &a, const int &b) -> bool {
return a < b;
});
then the argument for Comparator is deduced to be the type of the lambda closure object.
priority_queue, on the other hand, is a class template. There's no type deduction. You specify the template argument for Compare in the type of q, and afterwards, you can only supply a function argument (to the constructor) of the appropriate type.
To use a lambda with a priority queue, you'd need to get hold of its type:
auto compare = [](const int &a, const int &b) -> bool {
return a < b;
};
std::priority_queue<int, std::vector<int>, decltype(compare)> q(compare);
You were trying to pass a lambda expression as an argument to a template type parameter. This can't work. Doing the same with sort wouldn't work either:
sort<vector<int>::iterator, [](const int &a, const int &b) -> bool {
return a < b;
}>(/*...*/);
They are actually the same, the difference is in that one is a class template and the other a function template.
Here's what you can do with the priority queue:
auto comp = [](const int& a, const int& b) { return a < b; };
priority_queue<int, std::vector<int>, decltype(comp)> q(comp);
The difference is that for function templates, the compiler will deduce template parameters from the function parameters supplied, while it won't do that for class templates. So you have to supply the type explicitly, and with a lambda (which has an anonymous type), this is annoying.
Trying to override map::compare function using lambda, it seems that the following solution works.
auto cmp = [](const int&a, const int& b) { return a < b; };
std::map<int, int, decltype(cmp)> myMap(cmp);
But, I had to define cmp first and use it later.
Can I do this without defining 'cmp'?
No, you can't use lambda in unevaluated context -- i.e. template parameters as in your example.
So you must define it somewhere else (using auto) and then use decltype... the other way, as it was mentioned already is to use an "ordinal" functors
If your question is about "how to use lambda expression *once* when define a map" you can exploit implicit conversion of lambdas to std::function like this:
#include <iostream>
#include <functional>
#include <map>
int main()
{
auto m = std::map<int, int, std::function<bool(const int&, const int&)>>{
[](const int& a, const int& b)
{
return a < b;
}
};
return 0;
}
you may introduce an alias for that map type to reduce typing later...
#include <iostream>
#include <functional>
#include <map>
#include <typeinfo>
typedef std::map< int, int, std::function<bool(const int&, const int&)> > MyMap;
int main()
{
auto cmp = [](const int& a, const int& b) { return a < b; };
MyMap map(cmp);
return 0;
}
Using std::function to provide the appropriate type signature for the comparator type you can define your map type and then assign any lambda compare you wish to.
You could do something like this where the type of the map is deduced from the function you pass to a function.
#include <map>
template<class Key, class Value, class F>
std::map<Key, Value, F> make_map(const F& f) {
return std::map<Key, Value, F>{f};
}
int main() {
auto my_map = make_map<int, int>([](const int&a, const int& b) { return a < b; });
my_map[10] = 20;
}
I don't see a ton of reason for doing this but I wont say it's useless. Generally you want a known comparator so that the map can be passed around easily. With the setup above you are reduced to using template functions all the time like the following
tempalte<class F>
void do_somthing(const std::map<int, int, F>& m) {
}
This isn't necessarily bad but my instincts tell me that having a type which can ONLY be dealt with by generic functions is bad. I think it works out fine for lambda functions but that's about it. The solution here is to use std::function
#include <map>
#include <functional>
template<class Key, class Value>
using my_map_t = std::map<Key, Value, std::function<bool(const Key&, const Key&)>>;
int main() {
my_map_t<int, int> my_map{[](const int&a, const int& b) { return a < b; }};
my_map[10] = 20;
}
Now you can use any predicate you want and you have a concrete type to work with, my_map
hope this helps!
In C++20 you can do this:
std::map<int, int, decltype([](const int&a, const int& b) { return a < b; })> myMap;
int main() {
myMap.insert({7, 1});
myMap.insert({46, 2});
myMap.insert({56, 3});
for (const auto& [key,value]:myMap) {
std::cout << key << " " << value << std::endl;
}
}
I have a container object :
R Container;
R is of type list<T*> or vector<T*>
I am trying to write the following function:
template<typename T, typename R>
T& tContainer_t<T, R>::Find( T const item ) const
{
typename R::const_iterator it = std::find_if(Container.begin(), Container.end(), [item](const R&v) { return item == v; });
if (it != Container.end())
return (**it);
else
throw Exception("Item not found in container");
}
When trying the method (v is an object of my class)
double f = 1.1;
v.Find(f);
I get binary '==' : no operator found which takes a left-hand operand of type 'const double' (or there is no acceptable conversion)
I am confused with the lambda expression syntax and what i should write there and couldn't find any friendly explanation.
What is wrong ? 10x.
Missing a bit of context, but I note:
You return **it so you possibly want to compare *v==itemt
You pass const R&v where I suspect you meant const T&v into the lambda
You used a const_iterator, but returned a non-const reference. That was a mismatch
I made some params const& for efficiency (and to support non-copyable/non-movable types)
Here is working code, stripped of the missing class references:
#include <vector>
#include <algorithm>
#include <iostream>
template<typename T, typename R=std::vector<T> >
T& Find(R& Container, T const& item )
{
typename R::iterator it = std::find_if(Container.begin(), Container.end(), [&item](const T&v) { return item == v; });
if (it != Container.end())
return *it;
else
throw "TODO implement";
}
int main(int argc, const char *argv[])
{
std::vector<double> v { 0, 1, 2, 3 };
Find(v, 2.0); // not '2', but '2.0' !
return 0;
}
I have trouble describing my problem so I'll give an example:
I have a class description that has a couple of variables in it, for example:
class A{
float a, b, c, d;
}
Now, I maintain a vector<A> that contains many of these classes. What I need to do very very often is to find the object inside this vector that satisfies that one of it's parameters is maximal w.r.t to the others. i.e code looks something like:
int maxi=-1;
float maxa=-1000;
for(int i=0;i<vec.size();i++){
res= vec[i].a;
if(res > maxa) {
maxa= res;
maxi=i;
}
}
return vec[maxi];
However, sometimes I need to find class with maximal a, sometimes with maximal b, sometimes the class with maximal 0.8*a + 0.2*b, sometimes I want a maximal a*VAR + b, where VAR is some variable that is assigned in front, etc. In other words, I need to evaluate an expression for every class, and take the max. I find myself copy-pasting this everywhere, and only changing the single line that defines res.
Is there some nice way to avoid this insanity in C++? What's the neatest way to handle this?
Thank you!
I know this thread is old, but i find it quite useful to implement a powerful argmax function in C++.
However, as far as i can see, all the given examples above rely on std::max_element, which does comparison between the elements (either using a functor or by calling the operator<). this can be slow, if the calculation for each element is expensive. It works well for sorting numbers and handling simple classes, but what if the functor is much more complex? Maybe calculating a heuristic value of a chess position or something else that generate a huge tree etc.
A real argmax, as the thread starter mentioned, would only calculate its arg once, then save it to be compared with the others.
EDIT: Ok i got annoyed and had too much free time, so i created one < C++11 and one C++11 version with r-value references, first the C++11 version:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT && it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
template<typename IteratorT, typename HeuristicFunctorT>
inline IteratorT argmax(const IteratorT & begin, const IteratorT & end, const HeuristicFunctorT & functor) {
return argmax(IteratorT(begin), end, functor);
}
class IntPairFunctor : public std::unary_function< std::pair<int, int>, int > {
public:
int operator() (const std::pair<int, int> & v) const {
return v.first + v.second;
}
};
std::pair<int, int> rand_pair() {
return std::make_pair(rand(), rand());
}
int main(int argc, const char **argv) {
srand(time(NULL));
std::vector< std::pair<int, int> > ints;
std::generate_n(std::back_insert_iterator< std::vector< std::pair<int, int> > >(ints), 1000, rand_pair);
std::vector< std::pair<int, int> >::iterator m (argmax(ints.begin(), ints.end(), IntPairFunctor()));
std::cout << std::endl << "argmax: " << *m << std::endl;
}
The non C++11 version is much simpler, only the template:
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
Note that neither version requires any template arguments, the only requirement is that the heuristic implements the unary_function class
template <typename F>
struct CompareBy
{
bool operator()(const typename F::argument_type& x,
const typename F::argument_type& y)
{ return f(x) < f(y); }
CompareBy(const F& f) : f(f) {}
private:
F f;
};
template <typename T, typename U>
struct Member : std::unary_function<U, T>
{
Member(T U::*ptr) : ptr(ptr) {}
const T& operator()(const U& x) { return x.*ptr; }
private:
T U::*ptr;
};
template <typename F>
CompareBy<F> by(const F& f) { return CompareBy<F>(f); }
template <typename T, typename U>
Member<T, U> mem_ptr(T U::*ptr) { return Member<T, U>(ptr); }
You need to include <functional> for this to work. Now use, from header <algorithm>
std::max_element(v.begin(), v.end(), by(mem_ptr(&A::a)));
or
double combination(A x) { return 0.2 * x.a + 0.8 * x.b; }
and
std::max_element(v.begin(), v.end(), by(std::fun_ptr(combination)));
or even
struct combination : std::unary_function<A, double>
{
combination(double x, double y) : x(x), y(y) {}
double operator()(const A& u) { return x * u.a + y * u.b; }
private:
double x, y;
};
with
std::max_element(v.begin(), v.end(), by(combination(0.2, 0.8)));
to compare by a member or by linear combinations of a and b members. I split the comparer in two because the mem_ptr thing is damn useful and worth being reused. The return value of std::max_element is an iterator to the maximum value. You can dereference it to get the max element, or you can use std::distance(v.begin(), i) to find the corresponding index (include <iterator> first).
See http://codepad.org/XQTx0vql for the complete code.
This is what functors and STL are made for:
// A class whose objects perform custom comparisons
class my_comparator
{
public:
explicit my_comparator(float c1, float c2) : c1(c1), c2(c2) {}
// std::max_element calls this on pairs of elements
bool operator() (const A &x, const A &y) const
{
return (x.a*c1 + x.b*c2) < (y.a*c1 + y.b*c2);
}
private:
const float c1, c2;
};
// Returns the "max" element in vec
*std::max_element(vec.begin(), vec.end(), my_comparator(0.8,0.2));
Is the expression always linear? You could pass in an array of four coefficients. If you need to support arbitrary expressions, you'll need a functor, but if it's just an affine combination of the four fields then there's no need for all that complexity.
You can use the std::max_element algorithm with a custom comparator.
It's easy to write the comparator if your compiler supports lambda expressions.
If it doesn't, you can write a custom comparator functor. For the simple case of just comparing a single member, you can write a generic "member comparator" function object, which would look something like this:
template <typename MemberPointer>
struct member_comparator
{
MemberPointer p_;
member_comparator(MemberPointer p) : p_(p) { }
template <typename T>
bool operator()(const T& lhs, const T& rhs) const
{
return lhs.*p_ < rhs.*p_;
}
};
template <typename MemberPointer>
member_comparator<MemberPointer> make_member_comparator(MemberPointer p)
{
return member_comparator<MemberPointer>(p);
}
used as:
// returns an iterator to the element that has the maximum 'd' member:
std::max_element(v.begin(), v.end(), make_member_comparator(&A::d));
You could use the std::max_element STL algorithm providing a custom comparison predicate each time.
With C++0x you can even use a lambda function for it for maximum conciseness:
auto maxElement=*std::max_element(vector.begin(), vector.end(), [](const A& Left, const A& Right) {
return (0.8*Left.a + 0.2*Left.b)<(0.8*Right.a + 0.2*Right.b);
});
Sample of using max_element/min_element with custom functor
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct A{
float a, b, c, d;
};
struct CompareA {
bool operator()(A const & Left, A const & Right) const {
return Left.a < Right.a;
}
};
int main() {
vector<A> vec;
vec.resize(3);
vec[0].a = 1;
vec[1].a = 2;
vec[2].a = 1.5;
vector<A>::iterator it = std::max_element(vec.begin(), vec.end(), CompareA());
cout << "Largest A: " << it->a << endl;
it = std::min_element(vec.begin(), vec.end(), CompareA());
cout << "Smallest A: " << it->a << endl;
}