Как создать unordered_map с типами, отличными от stl, такими как UnicodeString, из ICU?

Я хотел бы иметь возможность сделать это:

std::unordered_map<icu::UnicodeString, icu::UnicodeString> mymap;

Однако, когда я это делаю (и я начинаю его использовать), я получаю ошибки «не могу преобразовать size_t в UnicodeString». Итак, я осмотрелся и прочитал о неупорядоченных контейнеры. В этом сообщении в блоге подчеркивается, что мне нужно сделать доступной специализацию std::hash<icu::UnicodeString>, поэтому я сделал именно это:

namespace std
{
    template<>
    class hash<icu::UnicodeString> {
    public:
        size_t operator()(const icu::UnicodeString &s) const 
        {
            return (size_t) s.hashCode();
        }
    };
};

Не идеально, однако, удовлетворяет требованиям. Однако теперь я получаю ошибки, связанные с:

error C2039: 'difference_type' : is not a member of 'icu_48::UnicodeString'

Сам пост в блоге намекает, что мне нужно делать больше; однако он не говорит мне, что мне делать, заканчивая следующими замечаниями:

В дополнение к хэш-функции неупорядоченные контейнеры также должны иметь возможность проверять два ключа на равенство. Канонический способ сделать это — использовать версию operator==(), определенную в глобальном пространстве имен. Обычно это функция, которую вы привыкли создавать при создании новых классов, но если вы пропустите ее, вы столкнетесь с той же массой непонятных ошибок компилятора, что и ранее в этой статье.

Мне не пришлось касаться этого в этой статье, потому что стандартная библиотека уже определяет этот оператор для std::pair. Конечно, при использовании std::pair вы также должны убедиться, что у вас есть оператор равенства для T1 и T2.

Итак, теперь я немного запутался, потому что operator== определено для UnicodeString.

Итак, используя C++11, MSVC и GCC. Также компиляция с зависимостями Qt. Тогда мой вопрос: что еще мне нужно сделать, чтобы добавить icu::UnicodeString типов на неупорядоченную карту?

В соответствии с просьбой позже я пытаюсь перебрать карту. Сама карта является частью класса с именем this->mymap:

std::unordered_map<icu::UnicodeString, icu::UnicodeString>::const_iterator it;
for ( it = this->mymap.begin(); it != this->mymap.end(); ++it )
{
    // access it->first, it->second etc...
}

person Community    schedule 12.04.2012    source источник
comment
Похоже, код обрабатывает тип ключа или значения как итератор. Можете ли вы показать нам, как вы используете этот mymap?   -  person kennytm    schedule 12.04.2012
comment
@KennyTM, конечно; 2 секунды.   -  person    schedule 12.04.2012
comment
Я действительно не могу воспроизвести ничего из этого, не могли бы вы создать короткий автономный компилируемый пример желательно без ICU?   -  person bitmask    schedule 12.04.2012
comment
@KennyTM ваша подсказка позволила мне понять - кто-то оставил хороший mymap->insert(key, value), который неправильный неправильный неправильный - быстрое изменение использования operator[] устраняет эти проблемы. Хотите опубликовать свой комментарий в качестве ответа, чтобы я мог его принять?   -  person    schedule 12.04.2012
comment
Каноническим способом для них сделать это является версия operator==(), определенная в глобальном пространстве имен. Не слишком доверяйте этому сообщению... == должно быть определено в пространстве имен один из его аргументов, поэтому ADL подхватывает его.   -  person Matthieu M.    schedule 12.04.2012


Ответы (1)


Как обнаружил ОП,

кто-то оставил хороший mymap->insert(key, value) что неправильно неправильно неправильно

Поскольку неупорядоченная карта имеет метод вставки с двумя аргументами,

template <class P>
iterator insert(const_iterator hint, P&& obj);

компилятор попытается сопоставить key с const_iterator, поэтому, вероятно, запрашивается член типа difference_type (он является членом итератора).

Правильный способ вставить запись — вставить пару,

mymap.insert(std::make_pair(key, value));

или просто используйте метод "emplace",

mymap.emplace(key, value);
person kennytm    schedule 12.04.2012
comment
Как и обещал, поставьте себе большую зеленую галочку за подсказку об итераторе. Заставил меня посмотреть на участников, использующих итераторы, а затем, увидев это, я подумал - ох. Некоторые из наших пользовательских контейнеров имеют прототипы insert(key, val), и контейнер был перемещен в прототипы C++11, так что... проблема решена! Спасибо! - person ; 12.04.2012