如何在 c++ 中将字段从类传递到函数
How to pass fields from a class to function in c++?
换句话说:如何将各种字段从自定义类传递到单个函数?
现在详细介绍:我有一个包含类的std::vector
,例如CustomClass
我必须通过某些标准从该类的字段中提取结果,这些标准是此类中的字段,并以某种方式组合这些数据。
我解决这个问题的第一个方法是使用一个函数,该函数接受类的std::vector
作为参数,以便提取数据并返回std:map
。此映射中的关键是应根据其组合数据的条件类型,该值是包含来自此向量所有成员的组合数据的int
。
问题是标准不仅仅是一个 - 此类中的多个字段可以用作标准(为了方便起见,所有标准都std::string
,如果不是 - 我可以使函数模板化)。
对我来说,现在最简单的方法是使用几乎相同的代码制作数十个函数,每个函数都从此类中提取一个简单的具体字段。但是,更改可能需要对所有数十个功能进行类似的更改,这将是一个令人头疼的维护问题。但是在这个阶段,我想不出如何将这个类中的一个字段传递给单个函数......
下面是此类的示例代码:
// this is the class with data and criteria
class CustomClass
{
public:
std::string criteria1;
std::string criteria2;
std::string criteria3;
//... and others criteria
int dataToBeCombined;
// other code
};
// this is one of these functions
std::map<std::string, int> getDataByCriteria1(std::vector<CustomClass> aVector)
{
std::map<std::string, int> result;
foreach(CustomClass anObject in aVector)
{
if(result.find(anObject.criteria1)==result.end()) // if such of key doesn't exists
{
result.insert(std::make_pair(anObject.criteria1, anObject.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
}
}
return result;
}
以类似的方式,我应该使其他函数应该与CustomClass::criteria2
、CustomClass::criteria3
等一起使用。
我想将这些标准放在一个数组中,并仅将条件的数量传递给此函数,但该类将被其他人用于其他目的,并且字段必须易于阅读,因此这不是一个选项(即真实姓名不criteria1
, criteria2
等,但都是描述性的)。
有人有想法吗?
编辑:有人将我的问题提到"C++具有不同返回类型的相同函数参数",这显然是非常不同的 - 在我的情况下,函数每次都返回相同的类型,只是它采用的参数必须是类中的各种字段。
您可以使用指向成员的指针。在函数中std::string CustomClass::*pField
声明一个参数,用&CustomClass::criteriaN
传递它,用anObject.*pField
访问它。
查看有关该主题的更多信息:指向数据成员的指针。
如果所有"标准"都是同一类型,我没有看到一个优雅的解决方案,但你可以以某种方式"枚举"它们并使用它们的数量。
例如,您可以通过这种方式在CustomClass
中声明模板化getVal()
方法
template <int I>
const std::string & getVal () const;
并以这种方式逐个数字、逐个标准地实施它们(在类主体之外)
template <>
const std::string & CustomClass::getVal<1> () const
{ return criteria1; }
template <>
const std::string & CustomClass::getVal<2> () const
{ return criteria2; }
template <>
const std::string & CustomClass::getVal<3> () const
{ return criteria3; }
现在,您可以通过这种方式转换模板化函数getDataByCriteria()
getDataByCriteria1()
template <int I>
std::map<std::string, int> getDataByCriteria (std::vector<CustomClass> aVector)
{
std::map<std::string, int> result;
for (const auto & cc : aVector)
{
if ( result.find(cc.getVal<I>()) == result.end()) // if such of key doesn't exists
{
result.insert(std::make_pair(cc.getVal<I>(), cc.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
}
}
return result;
}
并以这种方式调用它
auto map1 = getDataByCriteria<1>(ccVec);
auto map2 = getDataByCriteria<2>(ccVec);
auto map3 = getDataByCriteria<3>(ccVec);
---编辑:为不同类型的标准添加了解决方案(仅C++14---
如果"标准"的类型不同,则略有不同。
该解决方案有效,但在 C++14 中,这要归功于auto
和decltype()
.
通过示例,如果
std::string criteria1;
int criteria2;
long criteria3;
您可以使用auto
声明getVal()
template <int I>
const auto & getVal () const;
并定义(auto
)getVal()
的所有版本
template <>
const auto & CustomClass::getVal<1> () const
{ return criteria1; }
template <>
const auto & CustomClass::getVal<2> () const
{ return criteria2; }
template <>
const auto & CustomClass::getVal<3> () const
{ return criteria3; }
并将auto
与decltype()
结合起来,可以这样修改getDataByCriteria()
template <int I>
auto getDataByCriteria (std::vector<CustomClass> aVector)
{
std::map<decltype(aVector[0].getVal<I>()), int> result;
for (const auto & cc : aVector)
{
if ( result.find(cc.getVal<I>()) == result.end()) // if such of key doesn't exists
{
result.insert(std::make_pair(cc.getVal<I>(), cc.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
}
}
return result;
}
该功能的使用保持不变(再次感谢auto
)
auto map1 = getDataByCriteria<1>(ccVec);
auto map2 = getDataByCriteria<2>(ccVec);
auto map3 = getDataByCriteria<3>(ccVec);
PS:注意:代码未测试
p.s.2 : 对不起,我的英语不好
您可以使用函数提取文件,例如
std::string extractFiled(const CustomClass &object, int which) {
switch (which) {
case 1:
return object.criteria1;
case 2:
return object.criteria2;
case 3:
return object.criteria3;
default:
return object.criteria1;
}
}
getDataByCriteria
添加一个参数来指示要使用的文件。或者你可以只使用宏来实现getDataByCriteria
。
您将其标记为 C++11,因此请使用可变参数模板。
class VariadicTest
{
public:
VariadicTest()
{
std::map<std::string, int> test1 = getDataByCriteria(testValues, criteria1);
std::map<std::string, int> test2 = getDataByCriteria(testValues, criteria2);
std::map<std::string, int> test3 = getDataByCriteria(testValues, criteria1, criteria2);
std::map<std::string, int> test4 = getDataByCriteria(testValues, criteria1, criteria3);
}
private:
std::string criteria1 = { "Hello" };
std::string criteria2 = { "world" };
std::string criteria3 = { "." };
std::vector<CustomClass> testValues = { {"Hello",1}, {"world",2},{ "!",3 } };
template<typename T> std::map<std::string, int> getDataByCriteria(std::vector<CustomClass> values, T criteria)
{
std::map<std::string, int> result;
//do whatever is needed here to filter values
for (auto v : values)
{
if (v.identifier == criteria)
{
result[values[0].identifier] = values[0].value;
}
}
return result;
}
template<typename T, typename... Args> std::map<std::string, int> getDataByCriteria(std::vector<CustomClass> values, T firstCriteria, Args... args)
{
std::map<std::string, int> result = getDataByCriteria(values, firstCriteria);
std::map<std::string, int> trailer = getDataByCriteria(values, args...);
result.insert(trailer.begin(), trailer.end());
return result;
}
};
您没有指定在满足条件的各种条件下要执行的实际操作,因此很难说它们实际上可以组合多少。
以下是使用 STL std::accumulate()
以及一些附加功能的可能解决方案。此示例是使用 Visual Studio 2015 编译的。
如果大多数功能可以组合成一个相当小的累加函数,这种方法是有意义的,因为大多数条件都以相同的方式处理。或者,您可以让 accumulate_op()
函数在处理一般情况本身时为特定情况调用其他函数。
您可以以此为开始并进行适当的修改。
一种这样的修改可能是摆脱使用std::map
来维护状态。由于使用这种方法,您将根据标准进行累积来遍历std::vector
,因此我不确定如果您正在积累,您甚至不需要使用std::map
来记住任何东西。
// map_fold.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <numeric>
// this is the class with data and criteria
class CustomClass
{
public:
CustomClass() : dataToBeCombined(0) {}
std::string criteria1;
std::string criteria2;
std::string criteria3;
//... and others criteria
int dataToBeCombined;
// other code
};
// This is the class that will contain the results as we accumulate across the
// vector of CustomClass items.
class Criteria_Result {
public:
Criteria_Result() : dataToBeCombined(0) {}
CustomClass myCriteria;
std::map<std::string, int> result1;
std::map<std::string, int> result2;
std::map<std::string, int> result3;
int dataToBeCombined;
};
// This is the accumulation function we provide to std::accumulate().
// This function will build our results.
class accumulate_op {
public:
Criteria_Result * operator ()(Criteria_Result * x, CustomClass &item);
};
Criteria_Result * accumulate_op::operator ()(Criteria_Result *result, CustomClass &item)
{
if (!result->myCriteria.criteria1.empty() && !item.criteria1.empty()) {
std::map<std::string, int>::iterator it1 = result->result1.find(item.criteria1);
if (it1 == result->result1.end()) // if such of key doesn't exists
{
result->result1.insert(std::make_pair(item.criteria1, item.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
it1->second += item.dataToBeCombined;
}
result->dataToBeCombined += item.dataToBeCombined;
}
if (!result->myCriteria.criteria2.empty() && !item.criteria2.empty()) {
std::map<std::string, int>::iterator it2 = result->result2.find(item.criteria2);
if (it2 == result->result2.end()) // if such of key doesn't exists
{
result->result2.insert(std::make_pair(item.criteria2, item.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
it2->second += item.dataToBeCombined;
}
result->dataToBeCombined += item.dataToBeCombined;
}
if (!result->myCriteria.criteria3.empty() && !item.criteria3.empty()) {
std::map<std::string, int>::iterator it3 = result->result3.find(item.criteria3);
if (it3 == result->result3.end()) // if such of key doesn't exists
{
result->result3.insert(std::make_pair(item.criteria3, item.dataToBeCombined));
}
else
{
// do some other stuff in order to combine data
it3->second += item.dataToBeCombined;
}
result->dataToBeCombined += item.dataToBeCombined;
}
return result;
}
int main()
{
Criteria_Result result;
std::vector<CustomClass> aVector;
// set up the criteria for the search
result.myCriteria.criteria1 = "string1";
result.myCriteria.criteria2 = "string2";
for (int i = 0; i < 10; i++) {
CustomClass xx;
xx.dataToBeCombined = i;
if (i % 2) {
xx.criteria1 = "string";
}
else {
xx.criteria1 = "string1";
}
if (i % 3) {
xx.criteria2 = "string";
}
else {
xx.criteria2 = "string2";
}
aVector.push_back (xx);
}
// fold the vector into our results.
std::accumulate (aVector.begin(), aVector.end(), &result, accumulate_op());
std::cout << "Total Data to be combined " << result.dataToBeCombined << std::endl;
std::cout << " result1 list " << std::endl;
for (auto jj : result.result1) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " result2 list " << std::endl;
for (auto jj : result.result2) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " result3 list " << std::endl;
for (auto jj : result.result3) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " Trial two nn" << std::endl;
result.myCriteria.criteria2 = "";
result.result1.clear();
result.result2.clear();
result.result3.clear();
result.dataToBeCombined = 0;
// fold the vector into our results.
std::accumulate(aVector.begin(), aVector.end(), &result, accumulate_op());
std::cout << "Total Data to be combined " << result.dataToBeCombined << std::endl;
std::cout << " result1 list " << std::endl;
for (auto jj : result.result1) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " result2 list " << std::endl;
for (auto jj : result.result2) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
std::cout << " result3 list " << std::endl;
for (auto jj : result.result3) {
std::cout << " " << jj.first << " " << jj.second << std::endl;
}
return 0;
}
这将生成如下输出:
Total Data to be combined 90
result1 list
string 25
string1 20
result2 list
string 27
string2 18
result3 list
Trial two
Total Data to be combined 45
result1 list
string 25
string1 20
result2 list
result3 list
- 声明没有默认构造函数的字段
- 聚合初始化和删除的复制构造函数,也称为不可复制的 obejcts 作为字段
- 如何创建一个函数来提取向量内部字符串中的字段?
- 用于基于成员字段或函数创建比较器的快捷方式
- sizeof 函数如何在带和不带位字段的结构上工作?(填充)
- 如何使用函数的输出初始化 const 数组结构字段?
- 将带有字段的表作为参数从C++传递给 Lua 函数?
- 将函数作为类字段传递
- C++销毁顺序:在类析构函数之前调用字段析构函数
- uninit_member:非静态类成员字段 m_cJobState.bstatus 未在此构造函数中初始化,也不在其调
- 带有 std::map 的模板函数给出错误:变量或字段声明为 void
- 模拟一个函数,该函数像操作员=和破坏者一样传播到每个字段
- 如何从具有多个对象/字段的类中调用方法函数
- 函数上的关键字'const'意味着对象字段完全只读?
- 模板类 + 委派构造函数 = 字段未初始化?(叮叮当当整)
- 如何匹配通过引用传递给模拟函数的结构字段
- 委托构造函数在使用类字段进行参数时会出现分段错误
- 超载构造函数中的未指定字段
- 析构函数是否可以不调用特定字段的析构函数
- 当指定初始化程序的顺序和字段声明不一致时,clang可以删除函数调用