代码之家  ›  专栏  ›  技术社区  ›  ark1974

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

c++
  •  0
  • ark1974  · 技术社区  · 7 年前

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

    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();
    
    }
    

    3 回复  |  直到 7 年前
        1
  •  2
  •   Caleth    7 年前

    也可以使用指向成员的指针,而不是使用宏。请注意,在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), ' ');
    }
    
        2
  •  0
  •   Rulle    7 年前

    如果你真的想得到一些可以推广的东西,并且你愿意求助于宏,你可以使用 higher order macros 为了这个。在您的例子中,首先要添加一个宏,声明结构的所有字段及其索引:

    #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
      }
    };
    

    能够 FOREACH_MACRO .

    小心使用这个技巧。

        3
  •  0
  •   ark1974    7 年前

    user463035818 这似乎是迄今为止最简单的解决方案。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();
    
    }