I have a struct containing 19 variables and I need to use different sorting algorithms to sort this struct, the thing is that it can be sorted by any of these variables. I'm wondering if there is any way to dynamically access this data in the struct, that way I can just write one method for the sort instead of writing 19 different methods that run the same sorting algorithm but on the different variables inside.
So I have my struct
struct team_stats{
float yards_per_game;
int total_points;
etc etc
team_stats* arr = new team_stats[32];
I want to do something like this (obviously it wont be a string cause this doesn't make sense, but just the idea behind this):
quickSort(arr, "yards_per_game"); // sorts by yards per game
quickSort(arr, "total_points"); // sorts by total points
quickSort(team_stats* arr, string field) {
while (i <= j) {
while (arr[i].field < pivot)
etc. etc.
Instead of doing it like this:
if (field == "yards_per_game")
quickSortYards(arr);
else if (field == "total_points")
quickSortPoints(arr);
quickSortYards(team_stats* arr) {
while (i <= j) {
while (arr[i].yards_per_game < pivot)
etc. etc.
quickSortPoints(team_stats* arr) {
while (i <= j) {
while (arr[i].total_points < pivot)
etc. etc.
because the latter would require me to have to write 38 different functions for just for sorting with one algorithm, and I feel like that is just a mess
Thank you
If all of your data fields had the same type, it would have been possible to implement using purely pointers-to-members and without using templates.
However, it looks like you have different types for different fields. In that case templates are the simplest way to go about it. For example, you can use something like this
template <typename T, typename M> void sort_by_field(T a[], size_t n, const M T::*p)
{
std::sort(a, a + n, [p](const T &l, const T &r) { return l.*p < r.*p; });
}
struct S
{
int a;
float b;
};
int main()
{
S s[100] = { ... };
sort_by_field(s, 100, &S::a);
sort_by_field(s, 100, &S::b);
}
It is easy to update the above sort_by_field function to accept custom comparator, instead of the hardcoded < comparison inside the lambda.
In the above version of sort_by_field I made pointer-to-member p a normal run-time function parameter. It is also possible to make it a compile-time template parameter. It is just a matter of finding the proper balance between run-time parameterization of the code (slower, but less code bloat) and compile-time parameterization (faster, but more code bloat).
It is also possible to implement it entirely without templates, using pure run-time parameterization, by replacing the pointer-to-member with byte offset and using qsort-style comparator callback. But this would become a significantly more involving and hackish C-style solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With