c++ класс std::map с универсальным ключом

У меня есть семейство классов, и каждому подклассу нужна карта, но ключи будут иметь разные типы, хотя они оба будут выполнять одни и те же операции с картой. Также значение в обоих случаях будет строкой. Пока у меня есть код, аналогичный приведенному ниже примеру, моя цель — повторно использовать код с помощью универсального ключа. Без использования каких-либо дополнительных библиотек, кроме STL

class A{
 public:
    /*
     * More code
     */
};


class subA1 : public A{
public:
    void insertValue(long id, std::string& value){
        if(_theMap.find(id) == _theMap.end())
        {
            _theMap[id] = value;
        }
    }

 private:
     std::map<long,std:string> _theMap;
};

class subA2 : public A{
public:
    void insertValue(std::string& id, std::string& value){
        if(_theMap.find(id) == _theMap.end())
        {
            _theMap[id] = value;
        }
    }
private:
     std::map<std::string,std:string> _theMap;

};

person ulitosCoder    schedule 01.11.2016    source источник
comment
Что вы имеете в виду под общим ключом? Другой шаблон? std::variant?   -  person πάντα ῥεῖ    schedule 02.11.2016
comment
Помимо разных типов карт, есть ли другие различия между подклассами?   -  person balki    schedule 02.11.2016
comment
balki: оба подкласса выполняют очень разные операции, но хранение и извлечение данных на карте идентично, а некоторые другие общие коды   -  person ulitosCoder    schedule 02.11.2016
comment
@ulitosCoder В этом случае это решение должно работать: stackoverflow.com/a/40370038/463758   -  person balki    schedule 02.11.2016


Ответы (3)


Вы можете объединить subA1 и subA2 в один класс шаблона, например:

class A{
 public:
    /*
     * More code
     */
};

template <typename KeyType>
class subA : public A {
public:
    void insertValue(const KeyType &id, const std::string& value) {
        if(_theMap.find(id) == _theMap.end()) {
            _theMap.insert(std::make_pair(id, value));
        }
    }

 private:
     std::map<KeyType, std:string> _theMap;
};

Затем вы можете создать typedefs по мере необходимости:

typedef subA<long> subA1;
typedef subA<std::string> subA2;

Или, если вам нужны фактические производные классы:

class subA1 : public subA<long>
{
    ...
 };

class subA2 : public subA<std::string>
{
    ...
};
person Remy Lebeau    schedule 02.11.2016
comment
Я думаю, что это хорошее решение, потому что мне нужно, чтобы класс A был абстрактным, поскольку я не знаю, какой конкретный экземпляр подкласса я собираюсь создать до времени выполнения. - person ulitosCoder; 02.11.2016

Просто сделайте суперкласс A шаблоном, переместите в него _theMap и insertValue() и используйте правильную версию шаблона в подклассах.

template <typename KeyT>
class A{
 public:
   void insertValue(KeyT id, std::string& value){
        if(_theMap.find(id) == _theMap.end())
        {
            _theMap[id] = value;
        }
    }

 private:
     std::map<KeyT, std:string> _theMap;
};

class subA1 : public A<long> {};

class subA2 : public A<std::string> {};
person Pedro Boechat    schedule 01.11.2016
comment
В зависимости от фактической связи между A, subA1 и subA2 может иметь смысл вместо этого объединить subA1 и subA2 в один шаблон subA, который содержит map и является производным от нешаблонного A. - person Remy Lebeau; 02.11.2016
comment
В комментарии он сказал, что оба подкласса выполняют очень разные операции, но хранение и поиск данных на карте идентичны. - person Pedro Boechat; 02.11.2016

Как насчет того, чтобы написать еще один небольшой базовый класс, скажем, C<T>, который является template typename T и включает только map<T, string> и вашу функцию insert. Тогда каждый новый подкласс A также будет подклассом C. Таким образом, ваш subA1 будет public A, public C<long> и т. д.

person grigor    schedule 01.11.2016