Xeverous Xeverous - 1 month ago 8
C++ Question

C++11: bind std::sort for user-defined type and then use that bind as an argument in ctor

This is complicated. I wanted to create a class than can hold a sorting algorithm (mostly to compare how they work). Array that is to be sorted will be of type:

std::vector<std::shared_ptr<Item>>
. I am going to use different functions to sort it, I have tested
std::sort()
with a function looking like
bool compare_func(std::shared_ptr<Item> const& a, std::shared_ptr<Item> const& b)
and it worked correctly

The algorithm class also contains other data, for example name (std::string) and amount (int) of items to be sorted

The problem begins when I want to create and put an object of type algorithm into
std::vector<std::shared_ptr<Algorithm>>


I have already found on SO that std::bind is not an object, so first I need to create something like this:

struct std_sort {
template <typename RndIt, typename Cmp>
void operator()(RndIt begin, RndIt end, Cmp cmp) {
std::sort(begin, end, cmp);
}
};


The problem begins when I try to add an object of type algorithm

vect.push_back(std::make_shared<Algorithm>(std::string("std::sort()"), zero, zero, amount,
std::bind
(
static_cast<void(*)
(
std::shared_ptr<Item> a,
std::shared_ptr<Item> b,
std::function
<bool(
std::shared_ptr<Item> const& c, std::shared_ptr<Item> const& d
)>
)>
(std_sort()), //error on this line
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3
)
));


The plan was to call this vector's algorithms to sort a gievn array, It would look like
vect[0](array.begin(), array.end(), compare_func);


Everything goes well except for the last argument, the expected argument is of this type:

typedef std::function
<void(
std::shared_ptr<Item> a,
std::shared_ptr<Item> b,
std::function
<bool(
std::shared_ptr<Item> const& c, std::shared_ptr<Item> const& d
)>
)>
sorting_function;


The error I get (from MinGW)

error: invalid static_cast from type 'std_sort' to type 'void (*)(std::shared_ptr<Item>, std::shared_ptr<Item>, std::function<bool(const std::shared_ptr<Item>&, const std::shared_ptr<Item>&)>)'


If I remove static_cast I get tons of typical template errors

Answer

First, this call:

vect[0](array.begin(), array.end(), compare_func);

Is giving iterators to vect[0], but expecting an actual instance. You should change the type of your sorting_function to:

typedef std::function
    <void(
            std::vector<std::shared_ptr<Item>>::iterator a,
            std::vector<std::shared_ptr<Item>>::iterator b,
            std::function
            <bool(
                std::shared_ptr<Item> const& c, std::shared_ptr<Item> const& d
            )>
    )>
    sorting_function;

Second, you can't bind to the struct directly, because it isn't a function. std_sort::operator(), however, is a function. But since it's a template, it gets a bit more complicated to set up:

std_sort inst();
auto fn = std::bind(
    &std_sort::operator()<const std::shared_ptr<Item>&,
                          std::less<std::shared_ptr<Item>>>,
    &inst, _1, _2);

Although, it seems you'd be better off creating an instance of std::function directly, and then binding to that.

sorting_function fn(std_sort());
vect.push_back(std::make_shared<Algorithm>(..., std::bind(fn, ...)));

Or even better, just use lambdas:

vect.push_back(std::make_shared<Algorithm>(...,
    [](std::vector<std::shared_ptr<Item>>::iterator first,
       std::vector<std::shared_ptr<Item>>::iterator last,
       std::function
            <bool(
                std::shared_ptr<Item> const& c, std::shared_ptr<Item> const& d
            )> compare_func) {
        std_sort()(first, last, compare_func);
    }));

Live Demo