缩写类似的数据成员

时间:2014-07-19 16:14:54

标签: c++ members

以下代码说明了问题:

struct Data {
    int numFriends, numAcquaintances, numDates;
    // etc...
};

enum Country {USA, Canada, China}; // etc...
enum Personality {Serious, Lazy, Funny}; // etc...
enum Height {SuperShort, Short, Medium, Tall, SuperTall};

class Religion {};

class Person {
    std::map<Country, Data> countryStats;
    std::map<Personality, Data> personalityStats;
    std::map<Religion*, Data> religionStats;
    std::map<Height, Data> heightStats;  // And suppose there are 20 such similar data members

    // The problem:
    void insertNumFriends (Country country, int num) {countryStats[country].numFriends = num;}
    void insertNumFriends (Personality personality, int num) {personalityStats[personality].numFriends = num;}
    void insertNumFriends (Religion* religion, int num) {religionStats[religion].numFriends = num;}
    // and tons of other necessary methods (how to capture all of these using templates?);

这是我提出的(不完整的)解决方案,即使注释掉的行要编译,由于所有if语句(实际上它只是它),它仍然不是一个好方法只要原方法):

#include <iostream>
#include <map>
#include <typeinfo>
#include <typeindex>

struct Data {
    int numFriends, numAcquaintances, numDates;
    // etc...
};

enum Country {USA, Canada, China, France}; // etc...
enum Personality {Serious, Lazy, Funny}; // etc...
enum Height {SuperShort, Short, Medium, Tall, SuperTall};

class Religion {};

template <typename T>  // new struct here
struct Stats {
    std::map<T, Data> map;
};

class Person {
    Stats<Country> countryStats;
    Stats<Personality> personalityStats;
    Stats<Religion*> religionStats;
    Stats<Height> heightStats;  // And suppose there are 20 such similar data members
//  template <typename T> static std::map<std::type_index, Stats<T>> statsMap;  // illegal
  public:
    template <typename T>
    void insertNumFriends (const T& t, int num) {
        if (typeid(T) == typeid(Country)) {countryStats.map[t].numFriends = num;}
        // lines below will not compile, and it's a terrible method anyway:
//      else if (typeid(T) == typeid(Personality)) personalityStats.map[t].numFriends = num;
//      else if (typeid(T) == typeid(Religion)) religionStats.map[t].numFriends = num;
//      else if (typeid(T) == typeid(Height)) heightStats.map[t].numFriends = num;
    }
    void showAllStats() const {  // for testing only
        for (int COUNTRY = USA; COUNTRY <= France; COUNTRY++) {
            auto it = countryStats.map.find(static_cast<Country>(COUNTRY));
            if (it != countryStats.map.end())
            std::cout << "Country " << COUNTRY << ": " << it->second.numFriends << " friends" << std::endl;
        }
    // etc...
    }
};


int main() {
    Person bob;
    bob.insertNumFriends (USA, 5);
    bob.insertNumFriends (France, 2);
//  bob.insertNumFriends (Funny, 3); // won't compile because insertNumFriends<T> is not complete
    bob.showAllStats();  // USA: 5 friends, France: 2 friends
}

什么是更好的(工作解决方案)?非循环访客模式或类似的东西?注意:人员有数据成员,如姓名,年龄,countryOfOrigin,身高等......实际上也代表一个人,而不仅仅是容器的接口(上面的容器数据成员是人的“记录”)。 / p>

2 个答案:

答案 0 :(得分:2)

一种可能的解决方案:模拟C ++ 1y变量模板

定义一个保存数据的函数,在这种情况下是映射:

template<typename T>
std::map<T,Data>& map()
{
    static std::map<T,Data> _map;

    return _map;
}

现在只制作一个通用插入函数:

template<typename T>
void insert_data( const T& key , const Data& data )
{
    map<T>()[key] = data;
}

答案 1 :(得分:1)

是的,Manu的解决方案非常简洁优雅!真漂亮!这是我的代码使用他的方法,最后我发现需要隐藏指向数据成员的指针

#include <iostream>
#include <map>

struct Data {
    int numFriends, numAcquaintances, numDates;
};

enum Country {USA, Canada, France};
class Religion {} *Islam = new Religion;

class Person {
    private:
        template<typename T>
        std::map<T, Data>& dataMap() {static std::map<T, Data> map;  return map;}           public:
        template<typename T>
        void insert (const T& key, int Data::*dataPtr, int num) {
            dataMap<T>()[key].*dataPtr += num;  // pointer to data members finally useful!
        }
        void print() {  // for testing the results only
            std::cout << "Number of American friends: " << dataMap<Country>()[USA].numFriends << std::endl;
            std::cout << "Number of Islamic acquantances: " << dataMap<Religion*>()[Islam].numAcquaintances << std::endl;
        }
};

int main() {
    Person bob;
    bob.insert (USA, &Data::numFriends, 10);
    bob.insert (Islam, &Data::numAcquaintances, 20);
    bob.print();  // USA friends = 10, Islamic acquaintances = 20
}