C ++,将结构特征作为参数传递给函数

时间:2018-12-28 19:30:13

标签: c++ struct parameters

首先,我想说这是我在stackOverflow上提出的第一个问题,因此,如果我不够清楚,我深表歉意。

我的问题是关于参数地引用函数内部的结构特征。我使用C ++。

我真正想要实现的是能够基于特定的结构特征(作为参数给出)对结构对象(或类对象)的向量进行排序。 我还想通过模板给出结构的类型,因此某些处理特定情况的变通办法可能通常无法正常工作。

我将简单说明我的意思。

比方说,我有一个名为“人类”的结构,具有以下特征:“年龄”,“身高”,“体重”。

我们还假设我有一个称为“人类”的“人类”对象向量。

假设我要创建一个函数,该函数可以根据我作为参数传递的内容将每个元素的年龄,身高或体重输出到屏幕上。

以下代码显然无法正常工作。我正在寻求执行此操作的正确方法。

struct human{
    int age;
    int height;
    int weight;
};

void show(vector<human> &elements, int value){
    for (int i=0; i<elements.size(); i++)
        cout << elements[i].value << endl;
}

int main{
    ...
    vector<human> mankind;
    ...
    show(mankind, age);
    show(mankind, height);
    show(mankind, weight);
    ...
    return 0;
}

我想指出的是,这个例子很简单。当然,如果我为每个功能创建单独的功能,或者使用了一种轻松的方式(例如,将字符串“ age”或“ height”或“ weight”作为参数传递,在函数内部进行检查并具有每个人都有一个完全独立的案例。

但是,这种变通办法在一般情况下是行不通的,特别是如果我有许多不同类型的结构(通过template Tvector< T >)和功能时。

3 个答案:

答案 0 :(得分:3)

一种实现方法是使用 pointers-to-members ,这是一种C ++功能,可让您创建指向structclass特定字段的指针

这里的语法可能看起来有些吓人,但实际上还不错。例如,下面是如何获取指向height结构的human字段的指针:

int human::* ptr = &human::height;

在这里,语法int human::* ptr的意思是

  1. 它是指向human类型内部内容的指针;
  2. 具体来说,它是指向int数据成员的指针;和
  3. 该数据成员是height字段。

一旦有了该指针,就可以将其与human结构结合起来,从而像这样隔离出该成员:

human agatha;
cout << agatha.*ptr << endl;

这里,.*运算符的意思是“拉出ptr所指向的字段。

在您的情况下,您可以像这样将事情放在一起:

void show(vector<human> &elements, int human::* value){
    for (int i=0; i<elements.size(); i++)
        cout << elements[i].*value << endl;
}

int main{
    ...
    vector<human> mankind;
    ...
    show(mankind, &human::age);
    show(mankind, &human::height);
    show(mankind, &human::weight);
    ...
    return 0;
}

答案 1 :(得分:2)

我更喜欢使用lambda方法解决此问题。如果该函数仅知道调用代码,则不知道将要打印的内容,则可以将lambda传递给包含要打印的代码的函数。这样,您就可以使函数完全通用

template <typename T, typename Func>
void show(vector<T> const& elements, Func f){
    for (auto const& e : elements)
        cout << f(e)<< endl;
}

然后您将其命名为

show(mankind, [](auto const& e){return e.age;});
show(mankind, [](auto const& e){return e.height;});
show(mankind, [](auto const& e){return e.weight;});

如果show需要按顺序显示此成员,则您甚至可以像

一样在调用std::sort时利用lambda
template <typename T, typename Func>
void show(vector<T>& elements, Func f){
    std::sort(elements.begin(), elements.end(), [=](auto const& lhs, auto const& rhs){return f(lhs) < f(rhs);});
    for (auto const& e : elements)
        cout << f(e)<< endl;
}

因此要打印的元素用于排序矢量并打印该元素。

答案 2 :(得分:1)

以下是对其他答案的一些思考和改进:

1)如果您的结构包含不同类型的成员,则必须使用指向每种类型的成员的指针来重载所有函数。否则,您必须使用类似的模板:

#include <vector>
#include <iostream>

struct human{
    int age;
    int height;
    float weight;
};

template<typename T>
void show(std::vector<human> &elements,  T human::* value){
    for (int i=0; i<elements.size(); i++)
        std::cout << elements[i].*value << std::endl;
} 

2)我发现lambda方法更灵活,因为它允许您使用组合功能,这些组合功能在实际应用程序中可能会有用:

// body-mass-index
auto bmi = [](const human& e) { return e.height / (e.weight * e.weight); };

show(mankind, bmi);

3)此外,lambda方法还允许您操纵功能以进行排序,过滤等:

auto inverse = [](auto func) {
    return [=](const human& e) { return -func(e);};
};

template<typename T, typename Func>
void sort(std::vector<T> &elements, Func f) {
    std::sort(elements.begin(), elements.end(), [=](auto const &lhs, auto const &rhs) { return f(lhs) < f(rhs); });
}

sort(mankind, inverse(bmi));

4)如果将lambda放入全局变量(请参见上面的bmi示例),则lambda方法允许您在调用站点上完全使用指定的语法。

5)从C ++ 14开始,我们有了通用的lambda,因此您可以将lambda重用于多种不同类型的结构。