首先,我想说这是我在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;
}
我想指出的是,这个例子是一个非常简单的例子。当然,如果我为每个功能制作单独的函数,或者如果我使用一种厚颜无耻的方式,比如传递字符串"年龄"、"身高"或"体重"作为参数,在函数中进行检查,并为每个功能设置一个完全独立的大小写,我就可以做到这一点。
然而,这种变通方法在问题的一般情况下是不起作用的,尤其是如果我有许多不同类型的结构(通过template T
和vector< T >
传递)和特性。
实现这一点的一种方法是使用指向成员的指针,这是一个C++功能,允许您创建指向struct
或class
的特定字段的指针。
这里的语法看起来可能有点可怕,但实际上并没有那么糟糕。例如,以下是如何获得指向human
结构的height
字段的指针:
int human::* ptr = &human::height;
这里,语法int human::* ptr
表示
- 它是指向
human
类型内部某个内容的指针 - 具体地说,它是指向
int
数据成员的指针;以及 - 该数据成员是CCD_ 10字段
一旦你有了这个指针,你就可以将它与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;
}
对于这个问题,我更喜欢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;
}
因此,要打印的元素被用于排序向量和打印元素。
以下是对其他答案的一些思考和改进:
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放入全局变量中,则lambda方法允许您在调用站点上完全使用指定的语法(请参见上面的bmi示例)。
5) 从C++14开始,我们有通用的lambda,因此您可以为多种不同类型的结构重用lambda。