在循环中按顺序遍历成员变量

Traversing member variables sequentially in a loop

本文关键字:遍历 成员 变量 顺序 循环      更新时间:2023-10-16

这是我在循环中按顺序遍历类/结构中成员变量的实现,下面是一个典型的例子。我的实现看起来很难看,看起来像是用蛮力实现的。如何改进或推广。我想像链接列表的节点->下一个或数组中那样遍历变量?征求意见。提前感谢大师。

typedef struct {
string name;
string address;
string phone;
void set(const int idx, string str) {
idx == 0 ? name = str : idx == 1 ? address = str : phone = str;
}
void print() const {
std::cout << name << "-" << address << "-" << phone << 'n';
}
} Person ;
int main()
{
Person p;
string str;
stringstream ss{ "John London 9735048383" };
int idx = 0;
while (std::getline(ss, str, ' ')) {
p.set(idx++,str); // Traversing the member variables.  The member variables will take turn to set their values in order.
}
p.print();
}

已编辑:所有成员变量的类型相同。

您也可以使用指向成员的指针,而不是使用宏。请注意,在C++中,您不必使用typedef struct

struct Person {
std::string name;
std::string address;
std::string phone;
void print() const {
std::cout << name << "-" << address << "-" << phone << 'n';
}
};
int main()
{
Person p;
std::string str;
std::stringstream ss{ "John London 9735048383" };
std::vector<std::string(Person::*)> members = { &Person::name, &Person::address, &Person::phone };
for (auto it = members.begin(); std::getline(ss, str, ' ') && it != members.end(); ++it) {
std::invoke(*it, p) = str;
// Traversing the member variables.  The member variables will take turn to set their values in order.
}
p.print();
}

您可以使invoke稍微更容易接受,前提是您不关心停止流错误。

for (auto member : members)
{
std::getline(ss, invoke(member, p), ' ');
}

如果你真的想要一些可以通用的东西,并且你愿意使用宏,你可以使用更高阶的宏。在您的情况下,您将首先添加一个宏,声明结构的所有字段及其索引:

#define FOREACH_FIELD(OP)                       
OP(0, name)                                   
OP(1, address)                                
OP(2, phone)

然后,您将使用此宏来实现Person结构:

struct Person {
#define DECLARE_VAR(index, name) std::string name;
FOREACH_FIELD(DECLARE_VAR)
#undef DECLARE_VAR
void setField(int i, const std::string& value) {
switch (i) {
#define SET_FIELD(index, name) case index: name = value; break;
FOREACH_FIELD(SET_FIELD)
#undef SET_FIELD
};
}
void print() {
#define PRINT_FIELD(index, name) 
std::cout << #name << ": '" << name << "'" << std::endl;
FOREACH_FIELD(PRINT_FIELD)
#undef PRINT_FIELD
}
};

它看起来很难看,我建议你在采用上述技术之前仔细考虑一下。一般来说,C++中避免使用宏。它使代码更难阅读,但如果你有很多字段,那么,你可以使用它。它可以使代码更易于维护。毕竟,要添加新字段,只需更新FOREACH_MACRO即可。

小心使用此技巧

std::array似乎按照用户463035818的建议对我有效,这似乎是迄今为止最简单的解决方案。std::map将具有额外的优势,可以和别名一起使用。

typedef struct {
std::array<string, 3> data;
void print() const {
std::cout << data[0] << "-" << data[1] << "-" << data[2] << 'n';
}
} Person ;
int main()
{
Person p;
string str;
stringstream ss{ "John London 9735048383" };
int idx = 0;
while (std::getline(ss, str, ' ')) {
p.data[idx++] = str; 
}
p.print();
}