简体   繁体   English

C ++:为std :: sort提供模板化比较函数

[英]C++: Supplying a templated compare function to std::sort

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. 假设我想让std :: sort根据指针指向的int的值对指向int的指针进行排序。 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. 并提供给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. 或者其他什么,将它提供给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: 现在,这就是它变得棘手的地方:如果我们想要将任何类型的指针向量排序,使用任意比较函数(我们假设我们使用该函数的任何类型,将能够使用它) ) - 提供上面sort_helper函数的模板版本很简单:

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? 如何使用提供给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'] [编辑:由于各种原因,我正在寻找一个也适用于C ++ 03的解决方案 - 感谢Nir为他的C ++ 14回答']

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; 这里我明确指出了T; 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. 你可能有额外的编程来推断T但是让它对函数对象和函数指针都正常工作可能会非常棘手。

Edit: to make this work in C++03, we have to obviously remove our usage of lambdas. 编辑:为了使这个工作在C ++ 03中,我们显然必须删除lambda的用法。 Converting a lambda to a function object is pretty straightforward though. 将lambda转换为函数对象非常简单。 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; 编辑:我在03示例中模拟了调用操作符; 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 . 要用lambda做这个,你需要C ++ 14,而不仅仅是11.如果你使用03形式,那么你不需要显式指定<int>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). 哪个打印10 (真假)。 Note that this takes a function object rather than a function pointer, which is more idiomatic in C++. 请注意,这需要一个函数对象而不是函数指针,这在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): 你不能在c ++中传递函数模板指针,你可以做的是用operator()模板创建仿函数(与lambda非常类似,带有自动参数):

#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. 请记住,运算符必须具有const限定符,以使调用者能够从临时对象访问它。

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. 您正在尝试将类型comparison_function值传递给期望类型的模板。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM