Я реализовал hashmap в C++, чтобы узнать больше об ассоциативных картах в целом, и все работает хорошо, за исключением одной точки привязки - я хочу, чтобы программист мог создавать карты с произвольной параметризацией (например, [используя std::string
например] HashMap<string,string*>
, HashMap<string,string>
и HashMap<string*,string>
и т.д. являются законными).
Проблема в том, что в функции HashMap::get(int key_data)
возвращаемое значение карты в пропуске (где данный ключ не соответствует каким-либо сопоставленным значениям) не может быть просто NULL
если я поддерживаю наличие объектов в качестве значений карты. Я мог бы get(...)
функцию get(...)
всегда возвращать указатель на параметризованную карту Тип значения, но если этот тип уже является указателем, я не могу использовать унарный оператор &
, и если это объект, который я должен использовать оператор &
. Я определенно не хочу использовать RTTI, поэтому вопрос следующий:
Как я могу разрешать типы возвращаемых объектов и типов-указателей-объектов из моей функции HashMap::get()
, которая также требуется для пропусков?
Имейте в виду, что я использую gcc 4.7 с включенным C++ 11, поэтому все функции C++ 11 и оговорки применяются. Ниже приведена моя функция HashMap::get()
до тех пор, используя "всегда возвращать указатель на любую парадигму value_data":
template <class key_data,class value_data> value_data*
HashMap<key_data,value_data>::get(key_data dk) {
int key = keyGen(dk);
int hash_val = HashFunc(key);
HashNode* entry = _table[hash_val];
while (entry != 0) {
if (entry->getCurrentKey() == key) {
//value_data val = entry->getCurrentValue(); //this temporary will be
//gone from the stack quickly and therefore the returned pointer to a
//pointer (if value_data is a pointer) will segfault
return &(entry->getCurrentValue()); //this should be legal and yield
//a pointer to a pointer (iff value_data was a pointer), but instead
//I get a compiler error claiming
//operator & requires an lvalue operand...
}
entry = entry->next();
}
printf("Your get of int key %i resulted in no hits."
"The returned pointer to Value is NULL!\n",key);
return NULL;
}
Как указано в комментариях, строка return &(entry->getCurrentValue());
выдает ошибку компилятора, указывающую, что оператор &
требует операнда lvalue. Я могу избавиться от этой ошибки, поместив в value_data
значение value_data
, но это приведет к segfault, когда я действительно попытаюсь использовать его, потому что возвращенный указатель будет недействителен почти мгновенно. Просто используя ссылки на абстрактные данные, проблема синтаксиса не работает либо потому, что в этом случае пропуски не могут быть реализованы через возврат NULL
(ISO требует, чтобы ссылки, в отличие от исходных указателей, указывали на допустимые значения lvalues).
Если у кого-то есть предложение относительно обработки возвращенной ссылки, которая может быть "недействительной" (например, фиктивный объект, который может быть запрошен для достоверности, что все остальное наследует), я также открыт для них.
Одним из возможных способов решения этой проблемы будет частичная специализированная специализация. Например, как это сделать для указателей, см. Этот другой вопрос.
В принципе (скопированный из ответа там), вам понадобится
template <class I>
class GList<I*>
{
...
};
для предоставления специализированной версии списка для любого типа указателя.