首先,我想说这是我在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 T
和vector< T >
)和功能时。
答案 0 :(得分:3)
一种实现方法是使用 pointers-to-members ,这是一种C ++功能,可让您创建指向struct
或class
特定字段的指针
这里的语法可能看起来有些吓人,但实际上还不错。例如,下面是如何获取指向height
结构的human
字段的指针:
int human::* ptr = &human::height;
在这里,语法int human::* ptr
的意思是
human
类型内部内容的指针; int
数据成员的指针;和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重用于多种不同类型的结构。