如何将比较器 a-la std::less 传递给 C 样式 Qsort

How to pass a comparator a-la std::less to C-style Qsort?

本文关键字:样式 Qsort less 比较器 a-la std      更新时间:2023-10-16

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

问题是:我不知道该怎么做!我尝试使用 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);
}

但是我不知道如何实际将comp传递给它(因为我不能只写qsort(..., make_comparator(comp, a, b)),对吗?我尝试使用模板传递comp,但不知道如何传递。

所以我已经挣扎了一个小时了,而且我离解决方案并不近。正确的方法是什么?

你可以尝试这样的事情。 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");
}

您不能通过 qsortcmp传递给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);
}

并在稍后将comp设置为有效的函数指针

comp = <some function pointer>;

在打电话给qsort之前。

qsort(ptr, count, size, make_comparator);

如果选择遵循此方法,请确保在make_comparator中添加检查,以防止在未设置为有效函数时调用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);
}