Так что я искал вокруг форумов C ++ и не нашел решения. Я пытаюсь создать расширенную хэш-карту со следующими данными:
Возможность хранить значения как реальных, так и строковых.
Возможность хранить ключи как реальные, так и строковые.
Возможность хранить несколько записей (значений) для каждого ключа.
Пример вида результата:
ключ: «ключ» -> значение: 0,5, «45», «66».
ключ: 55 -> значение: «Yo», 27, «67», 88.
Как вы можете видеть, я пытаюсь создать хэш-карту, в которой я могу хранить ключ как действительный или как строковый +, сохраняя возможность хранить несколько ключей как действительный или как строковый для каждого ключа.
Если у вас нет аллергии на повышение, вы можете взглянуть на повышение :: вариант. Вы могли бы использовать boost::variant<double, std::string>
как ключ и тип значения в хэш-карте, или вы могли бы использовать std::vector<boost::variant<double, std::string>>
как тип значения в хэш-карте.
Среди других его достоинств (таких как безопасность типов), boost::variant
Тип ishable, если все его типы-члены являются hashable (и оба double
а также std::string
есть), поэтому вы должны иметь возможность использовать их в качестве ключей в хэш-таблице.
Поскольку C ++ является языком со статической типизацией, вы должны либо создать шаблон для любого класса, который вы создаете для этого, либо определить определенный тип для ключа и значения. В качестве альтернативы, вы можете использовать встроенный map<T>
тип, который доступен в стандартной библиотеке шаблонов, но опять же — нет способа определить, какой тип нужно использовать для параметра шаблона map<T>
во время выполнения.
Вы можете использовать что-то вроде двунаправленной карты. Boost имеет один, и вот код для одного, который я недавно написал:
// bimap.h
#pragma once
#include <string>
#include <list>
using namespace std;
template <typename T0, typename T1>
class bimap
{
public:
bimap(){}
bool Insert(T0, T1);
void Clear();
T0& operator[](T1);
T1& operator[](T0);
private:
list<pair<T0, T1>> m_dictionary;
};
template<typename T0, typename T1>
bool bimap<T0, T1>::Insert(T0 key, T1 value)
{
for (list<pair<T0, T1>>::const_iterator cur = m_dictionary.begin(); cur != m_dictionary.end(); cur++)
{
if ((*cur).first == key)
return false;
}
m_dictionary.push_back(make_pair(key, value));
return true;
}
template<typename T0, typename T1>
void bimap<T0, T1>::Clear()
{
m_dictionary.clear();
}
template<typename T0, typename T1>
T0& bimap<T0, T1>::operator[](T1 key)
{
for (list<pair<T0, T1>>::iterator cur = m_dictionary.begin(); cur != m_dictionary.end(); cur++)
{
if ((*cur).second == key)
return (*cur).first;
}
throw new out_of_range("Key does not exist.");
}
template<typename T0, typename T1>
T1& bimap<T0, T1>::operator[](T0 value)
{
for (list<pair<T0, T1>>::iterator cur = m_dictionary.begin(); cur != m_dictionary.end(); cur++)
{
if ((*cur).first == value)
return (*cur).second;
}
throw new out_of_range("Value does not exist.");
}
Преимущество двунаправленной карты состоит в том, что вы можете получить доступ к ключу, используя значение или значение, используя ключ. Недостатком (по крайней мере, с моим кодом, но я представляю и класс Boost) является то, что он не допускает множественных значений на ключ. Но было бы нетрудно изменить мой код, чтобы позволить это. Вам просто нужно изменить Insert()
метод, а затем подумайте, что следует вернуть из operator[]
которая берет ключ и возвращает значение, если для данного ключа есть несколько значений. Я не особо задумывался об этом, но мне кажется, что он может вернуть итератор, который можно использовать для перебора значений ключа.