如何将比较器a-la std :: less传递给C风格的Qsort?

时间:2021-12-13 22:51:40

So, I had an assignment to write a program to test speeds of different sorting algorithms, and one of them is good old qsort. I need to pass a comparator to it, but not the one it expects, but something boolean a-la std::less, and I know that to use it so that qsort accepts it, I need to actually pass it something like less(b, a) - less(a,b) --- this way, it has the range of [-1; 1] and produces what I need.

所以,我有一个编写程序来测试不同排序算法的速度的任务,其中一个是很好的旧qsort。我需要将一个比较器传递给它,但不是它所期望的那个,但是boolean a-la std :: less,我知道要使用它以便qsort接受它,我需要实际传递类似的东西( b,a) - less(a,b)---这样,它的范围为[-1; 1]并产生我需要的东西。

The problem is this: I have no idea how to actually do it! I tried to use lambda --- and (because I need to capture the comparator and qsort can't handle this) it failed. I tried to create another function converting my comparator to qsort's:

问题是:我不知道如何实际做到这一点!我试图使用lambda ---和(因为我需要捕获比较器而qsort无法处理这个)它失败了。我试图创建另一个函数将我的比较器转换为qsort:

int make_comparator(const void* a, const void* b) {
    return (int)comp(*(int*)b, *(int*)a) - (int)comp(*(int*)a, *(int*)b);
}

But I have no idea on how to actually pass the comp to it (because i can't just write qsort(..., make_comparator(comp, a, b)), can I?). I tried to use a template to pass comp, but couldn't figure out how.

但我不知道如何将comp实际传递给它(因为我不能只写qsort(...,make_comparator(comp,a,b)),我可以吗?)。我试图使用模板传递comp,但无法弄清楚如何。

So I'm struggling with it for like an hour already, and I'm no closer to a solution. What's the correct way to do this?

所以我已经挣扎了一个小时,而且我已经没有接近解决方案了。这样做的正确方法是什么?

2 个解决方案

#1


2  

You can try something like this. qsort_friendly_comparator just acts a wrapper around the comparator object. The only downside is that you have to manually specify the comparator type and its argument type.

你可以尝试这样的事情。 qsort_friendly_comparator只是作为比较器对象的包装器。唯一的缺点是您必须手动指定比较器类型及其参数类型。

#include <functional>
#include <cstdlib>
#include <cstdio>

// Assumes Comparator take two arguments of the same type and returns a bool.
// Have to manually specify the ArgType because it is tricky to deduce without
// excessive template magic.
template <typename Comparator, typename ArgType>
int qsort_friendly_comparator(const void *first, const void *second)
{
  Comparator comp;

  return (int)comp(*(ArgType*)second, *(ArgType*)first) -
         (int)comp(*(ArgType*)first,  *(ArgType*)second);
}

int main() {
  int data[] = {2, 1, 3, 0}; 

  qsort(data,
        /*num_elem=*/4,
        /*size_of_elem=*/sizeof(int),
        &qsort_friendly_comparator<std::less<int>, int>);

  for (int i = 0; i < 4; i++) {
    printf("%d ", data[i]);
  }
  printf("\n");
}

#2


1  

You cannot pass cmp to make_comparator via qsort. Your best option is to have a function pointer that is set to the right function.

你不能通过qsort将cmp传递给make_comparator。您最好的选择是将函数指针设置为正确的函数。

bool (*comp)(int a, int b) = nullptr;

int make_comparator(const void* a, const void* b) {
    return (int)comp(*(int*)b, *(int*)a) - (int)comp(*(int*)a, *(int*)b);
}

and later set comp to a valid function pointer

然后将comp设置为有效的函数指针

comp = <some function pointer>;

before calling qsort.

在调用qsort之前。

qsort(ptr, count, size, make_comparator);

If you choose to follow this approach, make sure to add checks in make_comparator to prevent calling cmp when it is not set to a valid function.

如果您选择遵循此方法,请确保在make_comparator中添加检查以防止在未将cmp设置为有效函数时调用cmp。

int make_comparator(const void* a, const void* b) {
    if ( comp == nullptr )
    {
       // Deal with error
    }
    return (int)comp(*(int*)b, *(int*)a) - (int)comp(*(int*)a, *(int*)b);
}

#1


2  

You can try something like this. qsort_friendly_comparator just acts a wrapper around the comparator object. The only downside is that you have to manually specify the comparator type and its argument type.

你可以尝试这样的事情。 qsort_friendly_comparator只是作为比较器对象的包装器。唯一的缺点是您必须手动指定比较器类型及其参数类型。

#include <functional>
#include <cstdlib>
#include <cstdio>

// Assumes Comparator take two arguments of the same type and returns a bool.
// Have to manually specify the ArgType because it is tricky to deduce without
// excessive template magic.
template <typename Comparator, typename ArgType>
int qsort_friendly_comparator(const void *first, const void *second)
{
  Comparator comp;

  return (int)comp(*(ArgType*)second, *(ArgType*)first) -
         (int)comp(*(ArgType*)first,  *(ArgType*)second);
}

int main() {
  int data[] = {2, 1, 3, 0}; 

  qsort(data,
        /*num_elem=*/4,
        /*size_of_elem=*/sizeof(int),
        &qsort_friendly_comparator<std::less<int>, int>);

  for (int i = 0; i < 4; i++) {
    printf("%d ", data[i]);
  }
  printf("\n");
}

#2


1  

You cannot pass cmp to make_comparator via qsort. Your best option is to have a function pointer that is set to the right function.

你不能通过qsort将cmp传递给make_comparator。您最好的选择是将函数指针设置为正确的函数。

bool (*comp)(int a, int b) = nullptr;

int make_comparator(const void* a, const void* b) {
    return (int)comp(*(int*)b, *(int*)a) - (int)comp(*(int*)a, *(int*)b);
}

and later set comp to a valid function pointer

然后将comp设置为有效的函数指针

comp = <some function pointer>;

before calling qsort.

在调用qsort之前。

qsort(ptr, count, size, make_comparator);

If you choose to follow this approach, make sure to add checks in make_comparator to prevent calling cmp when it is not set to a valid function.

如果您选择遵循此方法,请确保在make_comparator中添加检查以防止在未将cmp设置为有效函数时调用cmp。

int make_comparator(const void* a, const void* b) {
    if ( comp == nullptr )
    {
       // Deal with error
    }
    return (int)comp(*(int*)b, *(int*)a) - (int)comp(*(int*)a, *(int*)b);
}