使用变量访问Struct中的任何数据?

时间:2016-02-19 23:45:12

标签: c++ struct

我有一个包含19个变量的结构,我需要使用不同的排序算法来对这个结构进行排序,事实是它可以通过任何这些变量进行排序。我想知道是否有任何方法可以在结构中动态访问这些数据,这样我就可以编写一个方法来进行排序,而不是编写19个不同的方法来运行相同的排序算法但是在内部的不同变量上。

所以我有我的结构

struct team_stats{
    float yards_per_game;
    int total_points;
etc etc

team_stats* arr = new team_stats[32];

我想做这样的事情(很明显它不会是一个字符串,因为这没有意义,但只是背后的想法):

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.

而不是这样做:

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.

因为后者要求我必须编写38个不同的函数,仅用于使用一种算法进行排序,我觉得这只是一团糟

谢谢

3 个答案:

答案 0 :(得分:6)

如果您的所有数据字段都具有相同的类型,则可以使用纯pointers-to-members并且不使用模板来实现。

但是,看起来您对不同的字段有不同的类型。在这种情况下,模板是最简单的方法。例如,您可以使用类似这样的内容

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);
}

很容易更新上面的sort_by_field函数来接受自定义比较器,而不是lambda中的硬编码<比较。

sort_by_field的上述版本中,我将指向成员的p指向正常的运行时函数参数。也可以使它成为编译时模板参数。这只是在代码的运行时参数化(更慢,但代码膨胀更少)和编译时参数化(更快,但更多代码膨胀)之间找到适当平衡的问题。

也可以完全不使用模板,使用纯运行时参数化,通过使用字节偏移替换指向成员的指针并使用qsort样式的比较器回调来实现它。但是,这将成为一种更具参与性和最具攻击性的C风格解决方案。

答案 1 :(得分:1)

执行此操作的常规方法是使用谓词函数检查两个对象,并返回true / false,无论左侧对象是否小于右侧。在现代C ++中,您可以使用lambda:

执行此操作
auto sortByYards = [](const team_stats& lhs, const team_stats& rhs) -> bool {
    return lhs.yards_per_game < rhs.yards_per_game;
};

quickSort(arr, numTeams, sortByYards);

你的quickSort功能会有这样的指纹:

void quickSort(team_stats* arr, size_t numTeams, std::function<bool(const team_stats&, const team_stats&)> predicate) {
...
}

或者您可以使用using语句使其更具可读性:

using QuickSortPred = std::function<bool(const team_stats&, const team_stats&)>;
void quickSort(team_stats* arr, size_t numTeams, QuickSortPred predicate) {

您目前正在进行比较left < rightright > left,您将替换为

if (predicate(left, right))

(如果您进行了>次比较,只需将其切换为<,然后映射到谓词)

#include <algorithm>
#include <functional>
#include <iostream>
#include <string>

struct TeamStats {
    std::string name;
    float yards_per_game;
    int total_points;
};

using QuickSortPred = std::function<bool(const TeamStats&, const TeamStats&)>;
void quickSort(TeamStats* arr, size_t numTeams, QuickSortPred predicate)
{
    /// NOTE: This is NOT a complete quicksort, it's just to demonstrate
    /// the usage of predicate.

    for (size_t i = 0; i < numTeams - 1; ++i) {
        // before: if (arr[i] < arr[i+1])
        if (predicate(arr[i], arr[i+1]))
            std::swap(arr[i], arr[i+1]);
    }
}


int main() {
    TeamStats arr[] = {
        { "Red",   100, 30, },
        { "Blue",  150, 10, },
        { "Green", 200, 20, },
    };

    // approach one, store the lambda before hand
    auto sortByYards = [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
        return lhs.yards_per_game < rhs.yards_per_game;
    };
    quickSort(arr, 3, sortByYards);

    // approach two, write the lambda inline.
    quickSort(arr, 3, [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
        return lhs.total_points < rhs.total_points;
    });

    return 0;
}

现场演示:http://ideone.com/7qLtfV

如果我们要在现代C ++中正确地完成它,我们可能会使用除平面数组之外的容器来处理我们的可排序对象,例如向量。如果你的练习是开发一个快速排序例程,你需要用你自己的代码替换'std :: sort':)

#include <algorithm>
#include <functional>
#include <iostream>
#include <string>

struct TeamStats {
    std::string name;
    float yards_per_game;
    int total_points;
};

using QuickSortPred = std::function<bool(const TeamStats&, const TeamStats&)>;

template<typename I>
void quickSort(I begin, I end, QuickSortPred predicate)
{
    /// NOTE: This is NOT a complete quicksort, it's just to demonstrate
    /// the usage of predicate.

    std::sort(begin, end, predicate);   
}

int main() {
    std::vector<TeamStats> arr {
        { "Red",   100, 30, },
        { "Blue",  150, 10, },
        { "Green", 200, 20, },
    };

    // approach one, store the lambda before hand
    auto sortByYards = [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
        return lhs.yards_per_game < rhs.yards_per_game;
    };
    quickSort(arr.begin(), arr.end(), sortByYards);
    std::cout << "By yards:\n";
    for (auto& it : arr) {
        std::cout << it.yards_per_game << " " << it.name << "\n";
    }

    // approach two, write the lambda inline.
    quickSort(arr.begin(), arr.end(), [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
        return lhs.total_points < rhs.total_points;
    });
    std::cout << "By points:\n";
    for (auto& it : arr) {
        std::cout << it.total_points << " " << it.name << "\n";
    }

    return 0;
}

现场演示:http://ideone.com/N35RRn

如果您没有尝试编写自己的快速排序练习,可以删除所有快速排序的内容并将其归结为

#include <algorithm>
#include <functional>
#include <iostream>
#include <string>

struct TeamStats {
    std::string name;
    float yards_per_game;
    int total_points;
};

int main() {
    std::vector<TeamStats> arr {
        { "Red",   100, 30, },
        { "Blue",  150, 10, },
        { "Green", 200, 20, },
    };

    // approach one, store the lambda before hand
    auto sortByYards = [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
        return lhs.yards_per_game < rhs.yards_per_game;
    };
    std::sort(arr.begin(), arr.end(), sortByYards);
    std::cout << "By yards:\n";
    for (auto& it : arr) {
        std::cout << it.yards_per_game << " " << it.name << "\n";
    }

    // approach two, write the lambda inline.
    std::sort(arr.begin(), arr.end(), [](const TeamStats& lhs, const TeamStats& rhs) -> bool {
        return lhs.total_points < rhs.total_points;
    });
    std::cout << "By points:\n";
    for (auto& it : arr) {
        std::cout << it.total_points << " " << it.name << "\n";
    }

    return 0;
}

现场演示:http://ideone.com/vDSYtj

答案 2 :(得分:0)

你可以使用指向成员的指针映射并使用指针调用变量,这可能会给你一个提示

// typedef for the pointer-to-member
 typedef int X::*ptr_attr;

 // Declare the map of pointers to members
 map<string,ptr_attr> mattr;
 // Add pointers to individual members one by one:
 mattr["xx"] = &X::xx;
 mattr["yy"] = &X::yy;

// Now that you have an instance of x...
 X x;
// you can access its members by pointers using the syntax below:
 x.*mattr["xx"] = A["aa"];

参考: C++ Structs: get attribute by name