I have a project with a single .h
file and multiple .cpp
files. The header file contains a namespace UF
(abbreviation for useful functions) that currently implements sorting.
This is done by having a comparator defined in UF.cpp
thus:
int compar_int_asc(const void *a, const void *b)
{
int aa = *((int *)a), bb = *((int *)b);
if (base_arr_int[aa] < base_arr_int[bb])
return -1;
if (base_arr_int[aa] == base_arr_int[bb])
return 0;
if (base_arr_int[aa] > base_arr_int[bb])
return 1;
}
At present, the base array base_arr_int
that needs to be accessed by qsort
and the comparator function above is declared in main.cpp
and externed in UF.cpp
.
I access qsort
within a different class, SEP
as follows. Firstly, in SEP.cpp
, I extern base_arr_int
. Then, if ratios[100]
is an integer array that is native and local to SEP
, I do the following within SEP.cpp
.
base_arr_int = ratios;
qsort(indices, 100, sizeof(int), UF::compar_int_asc);
Is this the best way of implementing qsort with multiple classes?
In particular, I would like to avoid using global variables defined in main.cpp
as much as possible. Is there any alternative design?
The purpose of the global variable is to figuratively place the array inside the custom comparator. To eliminate the global variable, let's literally put ratio
into the custom comparator. To do so, the custom comparator cannot be an ordinary function or function pointer. It needs to be a function object. And std::sort
supports that.
Let's do it step by step.
So, you have an array that stores things.
int ratio[5] = {300, 400, 200, 500, 100};
But you don't want to sort it directly. You create an array of indices which actually gets sorted.
int index[5] = {0, 1, 2, 3, 4};
The goal is to sort index
. So let's write:
std::sort(index, index + 5);
But it is not what you want yet. You also need to pass a custom comparator index_comp
because the default less-than comparator is not what you need.
std::sort(index, index + 5, index_comp);
The rest of the work is how to write index_comp
. It is actually quite simple: lambda expression
auto index_comp = [&ratio](int index_left, int index_right) { return ratio[index_left] < ratio[index_right]; };
This lambda expression captures the array ratio
by reference ([&ratio]
). It has a parameter list taking two indices. The body compares the two actual objects in ratio
.
If you prefer the old school way, the lambda expression is just syntax sugar for the following:
class Compiler_Generated_Name
{
private:
int (&ratio)[5];
public:
Compiler_Generated_Name(int (&ratio_)[5]) : ratio(ratio_) {}
bool operator()(int index_left, int index_right)
{
return ratio[index_left] < ratio[index_right];
}
};
Compiler_Generated_Name index_comp(ratio);
The whole code:
#include <iostream>
#include <algorithm>
int main()
{
int ratio[5] = {300, 400, 200, 500, 100};
int index[5] = {0, 1, 2, 3, 4};
auto index_comp = [&ratio](int index_left, int index_right) { return ratio[index_left] < ratio[index_right]; };
std::sort(index, index + 5, index_comp);
for (int i = 0; i < 5; ++i)
std::cout << ratio[index[i]] << ' ';
}