C++: Supplying a templated compare function to std::sort - c++

Suppose I want to get std::sort to sort a vector of pointers to int's, based on the value of the int's the pointers point to. Ignore the obvious performance issue there. Simple huh?
Make a function:
bool sort_helper(const int *a, const int *b)
{
return *a < *b;
}
and supply to the std::sort.
Now, if we also want to do the same thing with a vector of pointers to large objects. The same thing applies:
first we define a < operator in the object, then make a function along the following lines:
bool sort_helper(const ob_type *a, const ob_type *b)
{
return *a < *b;
}
or whatever, supply that to std::sort.
Now, and this is where it gets tricky: what if we want to sort a vector of pointers to any type, with any arbitrary compare function (we make the assumption that whatever type we use that function with, will be able to work with it)- supplying a template version of the sort_helper function above is easy:
template <class ob_type>
bool sort_helper(const ob_type *a, const ob_type *b)
{
return *a < *b;
}
However, supplying an arbitrary compare function is harder: Something like this-
template <typename comparison_function, class ob_type>
bool sort_template_helper(const ob_type *a, const ob_type *b)
{
return comparison_function(*a, *b);
}
template <typename comparison_function, class iterator_type>
void t_sort(const iterator_type &begin, const iterator_type &end, comparison_function compare)
{
std::sort(begin, end, sort_template_helper<compare>);
}
is what I'd like to do, but doing this:
bool less_than(const int a, const int b)
{
return a < b;
}
void do_stuff()
{
t_sort(ipoint_vector.begin(), ipoint_vector.end(), sort_template_helper<less_than>);
}
Doesn't work.
How can I sort a vector of pointers to a known type, by the value of the objects pointed to, using an arbitrary comparison function, supplied to std::sort? Assume that the test case I am presenting here is an insanely simplified version of the actual scenario, and that there are valid reasons for wanting to do things this way, that would take too long to go into and distract from the problem.
[EDIT: for various reasons, am looking for a solution that also works in C++03 - Thanks to Nir for his C++14 answer tho']

Basically what you need is a higher order function: a function that returns a function.
template <class T, class F>
auto make_pointee_comparison(F f) {
return [=] (T const * l, T const * r) { return f(*l, *r); };
}
Here I have T be explicitly specified; you might be able with extra programming to deduce T but it can be quite tricky to make it work correctly for both function objects and function pointers.
Edit: to make this work in C++03, we have to obviously remove our usage of lambdas. Converting a lambda to a function object is pretty straightforward though. We declare a struct:
template <class F>
struct PointeeComparisonHelper {
PointeeComparisonHelper(F f) : m_f(f) {}
template <class T>
bool operator()(T const * l, T const * r) const {
return m_f(*l, *r);
}
F m_f;
};
template <class F>
PointeeComparisonHelper<F> make_pointee_comparison(F f) {
return PointeeComparisonHelper<F>(f);
}
Edit: I templated the call operator in the 03 example; to do this with a lambda you need C++14, not just 11. If you are using the 03 form, then you don't need to explicitly specify <int> to make_pointee_comparison.
Usage:
auto c = make_pointee_comparison<int>([] (int x, int y) { return x < y; });
int x = 5;
int y = 6;
std::cerr << c(&x, &y) << c(&y, &x);
Which prints 10 (true false). Note that this takes a function object rather than a function pointer, which is more idiomatic in C++. But you can pass a function pointer too:
bool compare(int x, int y) { return x > y; }
auto c2 = make_pointee_comparison<int>(&compare);
std::cerr << c2(&x, &y) << c2(&y, &x);
You could then write your function like this:
template <typename comparison_function, class iterator_type>
void t_sort(const iterator_type &begin, const iterator_type &end, comparison_function compare)
{
using deref_type = const decltype(*begin);
std::sort(begin, end, make_pointee_comparison<deref_type>(compare));
}

You cannot pass function template pointer in c++, what you can do is to create functor with operator() template (something very similar to lambda with auto parameters):
#include <algorithm>
#include <vector>
#include <cassert>
struct less {
template <class T>
bool operator()(T first, T second) const {
return first < second;
}
};
template <class Cmp>
struct cmp_ptr {
Cmp cmp;
cmp_ptr(Cmp cmp):cmp(cmp) { }
cmp_ptr() { }
template <class T>
bool operator()(T first, T second) const {
return cmp(*first, *second);
}
};
template <class Iter, class Cmp>
bool is_sorted(Iter beg, Iter end, Cmp cmp) {
Iter prev = beg;
Iter next = beg;
for (next++; next != end; prev++, next++) {
if (cmp(*next, *prev)) {
return false;
}
}
return true;
}
int main() {
std::vector<int*> v;
v.push_back(new int(10));
v.push_back(new int(1));
v.push_back(new int(5));
v.push_back(new int(7));
v.push_back(new int(3));
v.push_back(new int(2));
std::sort(v.begin(), v.end(), cmp_ptr<less>());
assert(::is_sorted(v.begin(), v.end(), cmp_ptr<less>()));
}
[live demo]
Remember that operator must have const qualifier to make caller to be able to access to it from temporary object.

guess you are looking for something like this:
template <typename comparison_function, class iterator_type>
void sort_deref(const iterator_type &begin, const iterator_type &end, comparison_function compare) {
std::sort(begin, end, [compare](auto *a, auto *b) { compare(*a,*b); });
}
// example usage:
sort_deref(std::begin(container), std::end(container), std::less<>());
You are trying to pass value of type comparison_function to a template expecting type.

Related

passing auto as an argument and returning auto in C++ [duplicate]

I am writing an identity function for some of my classes that keeps a count of its calls (long story -> short: metrics).
At the moment, I'm trying to figure the performance differences/benefits of using a template vs auto.
Here is a short example taken from my code of what I'm doing:
namespace Metrics {
unsigned long identifications = 0;
//auto version
auto identity(auto i) {
//... other stuffs
identifications++;
return i;
};
//template version
template<class I> I identity(I i) {
//... other stuffs
identifications++;
return i;
};
};
There's a bit more going on, but that is the basics. I know the compiler will just make a function for each, i.e.
identity(5);
identity("5");
//generates the functions
int identity(int i) { ... return i; };
const char* identity(const char* i) { ... return i; };
At run-time, which one is faster?
And do they have a compile time difference?
Since this function is meant to be called a lot, I'm more interested in run-time performance, but there also could be a large amount of types to generate the function for, so I'm also interested in which one would be faster at compile-time.
auto identity(auto i)
{
//...
return i;
}
is a shorthand for
template <class T>
auto identity(T i)
{
// ...
return i;
}
which in turn is a shorthand for
template <class T>
T identity(T i)
{
// ...
return i;
}
So no difference whatsoever.
Not applicable to your example, but if you are going to use auto parameters you need to be aware of some gotchas:
auto as return type
auto foo(auto a)
Does not mean
// not this
template <class T>
T foo(T a)
The return type will be deduced from the return expression(s) in foo definition, just like any auto return type. It just happens that in your function the return type is deduced to be the same as the parameter type.
Multiple auto parameters
void foo(auto a, auto b)
Is not equivalent to
// not this
template <class T>
void foo(T a, T b)
but with
template <class T, class U>
void foo(T a, U b)

Identity Function: Difference between templates and auto

I am writing an identity function for some of my classes that keeps a count of its calls (long story -> short: metrics).
At the moment, I'm trying to figure the performance differences/benefits of using a template vs auto.
Here is a short example taken from my code of what I'm doing:
namespace Metrics {
unsigned long identifications = 0;
//auto version
auto identity(auto i) {
//... other stuffs
identifications++;
return i;
};
//template version
template<class I> I identity(I i) {
//... other stuffs
identifications++;
return i;
};
};
There's a bit more going on, but that is the basics. I know the compiler will just make a function for each, i.e.
identity(5);
identity("5");
//generates the functions
int identity(int i) { ... return i; };
const char* identity(const char* i) { ... return i; };
At run-time, which one is faster?
And do they have a compile time difference?
Since this function is meant to be called a lot, I'm more interested in run-time performance, but there also could be a large amount of types to generate the function for, so I'm also interested in which one would be faster at compile-time.
auto identity(auto i)
{
//...
return i;
}
is a shorthand for
template <class T>
auto identity(T i)
{
// ...
return i;
}
which in turn is a shorthand for
template <class T>
T identity(T i)
{
// ...
return i;
}
So no difference whatsoever.
Not applicable to your example, but if you are going to use auto parameters you need to be aware of some gotchas:
auto as return type
auto foo(auto a)
Does not mean
// not this
template <class T>
T foo(T a)
The return type will be deduced from the return expression(s) in foo definition, just like any auto return type. It just happens that in your function the return type is deduced to be the same as the parameter type.
Multiple auto parameters
void foo(auto a, auto b)
Is not equivalent to
// not this
template <class T>
void foo(T a, T b)
but with
template <class T, class U>
void foo(T a, U b)

Process std::map<K,V> and std::map<K,V*> in similar way

I have two types: std::map<K,V> and std::map<K,V*>, and lot of functions, which operates with std::map<K,V> .
Now, I need also to process std::map<K,V*> objects by these functions . What is the best way to to implement processing the both types by the same code?
I have function
std::map<K,V>& Process( std::map<K,V>& gData)
{
for(auto && it: gData )
//some code
}
and a would like to be able use as well:
std::map<K,V*>& Process( std::map<K,V*>& gData)
I suspect, that I have to write two wrappers, that will call the 'realProcessing' code
std::map<K,V>& Process( std::map<K,V>& gData)
{
//...some here...
realProcessing(...some arguments...)
}
std::map<K,V*>& Process( std::map<K,V*>& gData)
{
//...another wrapper here...
realProcessing(...some arguments...)
}
the question is how to implemet this
You can add a layer of abstraction. Lets say you have:
std::map<int, int> value_map{{1,1},{2,2},{3,3}};
std::map<int, int*> pointer_map{{1,new int(1)},{2,new int(2)},{3,new int(3)}};
And you want to iterate them in the same function like:
template<typename K, typename V>
void process(std::map<K, V>& data)
{
for (auto& e : data)
{
// use e.second as an int if passed both maps
}
}
What you can do is add a couple functions that will return a reference to the element or what it points to like:
template<typename T>
T& get_value(T& element)
{
return element;
}
template<typename T>
T& get_value(T* element)
{
return *element;
}
Then you could implement process like:
template<typename K, typename V>
void process(std::map<K, V>& data)
{
for (auto& e : data)
{
auto& element = get_value(e.second);
// use element here
}
}
Live Example
Since C++17 you can also use if constexpr for these kind of situations, for example:
template <typename T>
auto get_value(T t) {
if constexpr (std::is_pointer_v<T>)
return *t; // deduces return type to int for T = int*
else
return t; // deduces return type to int for T = int
}

Make function generic with respect to pointers and references

Suppose I have this C++ function:
class C { ... };
void do(const vector<C>& cs) {
...
for (...) {
cs[i].do_whatever();
}
...
}
But C is expensive to copy so I might have something like this:
std::vector<C*> reorder_in_some_way(const std::vector<C>& cs) {
...
}
int main() {
std::vector<C> cs = ...;
std::vector<C*> reorderedCs = reorder_in_some_way(cs);
do(reorderedCs);
}
Obviously this won't work. I could get around it by giving up and just making do a template over any type like this:
template<typename T>
void do(const vector<T>& cs) {
But it really only works with C's and I'd like that to be encoded in the type system - and also it makes do() easier to understand if you don't have to go hunting around for places where it is used.
Is there any way to write do() so that it can generically take both vector<C> and vector<C*> (and for bonus points vector<reference_wrapper<C>>)?
Just write 2 template functions that applies a functor:
template<class T,typename Func>
void apply( const std::vector<T> &v, Func f )
{
for( const auto &i : v ) f( i );
}
template<class T,typename Func>
void apply( const std::vector<T*> &v, Func f )
{
for( auto i : v ) f( *i );
}
then pass a lambda:
std::vector<C> vc;
std::vector<C*> vp;
auto call = []( const C &c ) { c.do_whatever(); };
apply( vc, call );
apply( vp, call );
(note you cannot call your function do - it is a keyword in C++)
live example
PS As you mentioned in comments your function apply is rather complex so you prefer to have only one copy of it, in this case create a helper:
template<class T>
const T &apply_helper( const T *t ) { return *t; }
template<class T>
typename std::enable_if<!std::is_pointer<T>::value, const T &>::type
apply_helper( const T &t ) { return t; }
then write your apply function only once:
template<class T,typename Func>
void apply( const std::vector<T> &v, Func f )
{
for( const auto &i : v ) f( apply_helper( i ) );
}
live example N2
You might keep your do function generic, but specialize a getter for T& and T* that both return a T&:
namespace detail{
template<class T>
T& get(T& _in){
return _in;
}
template<class T>
T& get(T* _in){
return *_in;
}
} // namespace detail
template<class T>
void do_a_thing(const std::vector<T>& cs) {
for (size_t i = 0; i < cs.size(); ++i) {
detail::get(cs[i]).do_whatever();
}
}
Demo
Either way you are going to need to specialize between pointers and references. I think that this pushes it to the smallest scope.
If you want to constrain do_a_thing to only accept C or C*, we can create a small trait to do this:
template <class T>
struct is_c : std::false_type{};
template <>
struct is_c<C>: std::true_type{};
template <>
struct is_c<C*>: std::true_type{};
And then modify do_a_thing with std::enable_if:
template<class T, std::enable_if_t<is_c<T>::value, int> = 0>
void do_a_thing(const std::vector<T>& cs) {
for (size_t i = 0; i < cs.size(); ++i) {
detail::get(cs[i]).do_whatever();
}
}
For bonus points, we'll write another specialization of do_a_thing that gives a nice compiler error for types that do not satisfy the constraint:
template<class T>
struct always_false : std::false_type{};
template<class T, std::enable_if_t<!is_c<T>::value, int> = 0>
void do_a_thing(const std::vector<T>& cs) {
static_assert(always_false<T>::value, "do_a_thing only works for C and C*");
}
Now the following will fail:
struct Q{};
std::vector<Q> qs;
do_a_thing(qs); // compiler error
Demo
Write a function template that gets a pair of iterators (not a vector).
Then pass it either normal vector<C>::iterators, or adapted vector<C*>::iterators, e.g. boost::transform_iterator instances.
Working example:
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <boost/iterator/transform_iterator.hpp>
int& deref(int*& x) { return *x; }
template <class it>
void print(it from, it to)
{
std::copy(from, to, std::ostream_iterator<typename it::value_type>(std::cout, " "));
std::cout << "\n";
}
int main()
{
std::vector<int> a {4,3,7,1};
std::vector<int*> b {new int(2), new int(0), new int(11), new int(-3)};
// auto deref = [](int*& x) -> int& { return *x; };
// cannot use a lambda here because it's non-copyable
// and iterators must be copyable.
std::sort(std::begin(a), std::end(a));
std::sort(boost::make_transform_iterator(std::begin(b), &deref),
boost::make_transform_iterator(std::end(b), &deref));
print(std::begin(a), std::end(a));
print(boost::make_transform_iterator(std::begin(b), &deref),
boost::make_transform_iterator(std::end(b), &deref));
}
I think a possible solution could be to create a modified vector class that is generic with respect to pointerness, and can be implicitly converted to from a vector<T> or a vector<T*>. Like this:
template<typename T>
class VectorWrapper {
public:
VectorWrapper(const vector<T>& v) : reference(&v) { }
VectorWrapper(const vector<T*>& v) : pointer(&v) { }
const T& at(int idx) const {
if (reference)
return (*reference)[idx];
return *(*pointer)[idx];
}
// etc. for size() and so on. You could probably have
// this class derive from std::vector and reimplement its
// methods to switch between `reference` and `pointer`.
private:
const vector<T>* reference = nullptr;
const vector<T*>* pointer = nullptr;
};
void do_thing(VectorWrapper<C> wrapper) {
wrapper.at(0).whatever();
}
Not tested, and I don't think I'll go this route to be honest but it's the best I could come up with.

When writing generic code for smart pointers and pointers, how to get the simple pointer?

When I want to implement a function:
template <typename TIterator>
void doSomething(TIterator begin, TIterator end);
to be able to work with both:
std::vector<Widget*>
and
std::vector<std::shared_ptr<Widget>>
how should I access the underlying pointer? For some reason std::shared_ptr<Widget> is not implicitly convertible to Widget* and I have to use the get() function. This way, the code does not work for std::vector<Widget*> since Widget* has no get() function.
What I do is this:
void functionAcceptingPointer(Widget* widget);
template <typename TIterator>
void doSomething(TIterator begin, TIterator end);
{
std::map<double, decltype(&(**begin))> map;
...
auto firstPointer = &(**begin);
...
functionAcceptingPointer(&(**begin));
....
}
That is use the double dereference * followed by the & operator, whenever I need an ordinary pointer.
It does the job, but I am curious if there is some more readable, generally used way to do this and if there are some things that can come back to haunt me after I fill my code with ugly stuff like &(**begin)
Here's what I do to solve this problem:
#include <memory>
template <class T>
inline
T*
to_raw_pointer(T* p) noexcept
{
return p;
}
template <class Pointer>
inline
typename std::pointer_traits<typename std::remove_reference<Pointer>::type>::element_type*
to_raw_pointer(Pointer&& p) noexcept
{
return ::to_raw_pointer(p.operator->());
}
int main()
{
std::shared_ptr<int> p1(new int(1));
int* r1 = to_raw_pointer(p1);
int* p2 = new int(2);
int* r2 = to_raw_pointer(p2);
}
To increase the readability, you can create your own wrapper to dereference any (smart) pointer:
template<typename T> auto raw_deref(T t) -> decltype( &**t ) { return &**t; }
which would turn your code into
template <typename TIterator>
void doSomething(TIterator begin, TIterator end)
{
std::map<double, decltype(raw_deref(begin))> map;
...
auto firstPointer = raw_deref(begin);
...
functionAcceptingPointer(raw_deref(begin));
....
}
and of course you could think of a better name than raw_deref :)