Можете ли вы превратить std :: map в неупорядоченную карту с помощью специального компаратора? - PullRequest
1 голос
/ 22 мая 2019

Из-за использования библиотеки, для которой я не хочу редактировать код, я обнаружил, что мне нужно использовать std::map<Identifier, String>.

struct compareIdentifiers
{
    bool operator()(const Identifier& a, const Identifier& b) const
    {
        // return a < b;
        return true;
    }
};

typedef std::map<Identifier, String, compareIdentifiers> IdentifierMap;

Должен ли я вернуть значение true или false?Нет необходимости сравнивать.Я полагаю, что возвращение true или возвращение false будет сильно отличаться по эффективности, потому что одно приведет к переупорядочению карты, а другое не будет ... верно?

Я пытался использовать std::unordered_map<Identifier, String>, но получил ошибку:

Ошибка C2280 'std :: hash <_Kty> :: hash (void)': попытка обратиться к удаленной функции

Ответы [ 4 ]

7 голосов
/ 22 мая 2019

Всегда возвращать истину неверно.Это будет означать (например), что A < B и B < A оба будут истинными.Это противоречит требованиям std::map компаратора, которые заключаются в том, что он налагает строго слабый порядок .Вполне возможно, что возвращение true может привести к сбою вашей программы.

Всегда возвращать false допустимо, это фактически означает, что все ключи считаются равными.Так что на карту можно добавить только один ключ (спасибо aschepler за исправление).

Что мешает вам написать разумный компаратор?

4 голосов
/ 22 мая 2019

Я пытался использовать std :: unordered_map, но получил ошибку:

Ошибка C2280 'std :: hash <_Kty> :: hash (void)': попытка сослаться на удаленную функцию

Это связано с тем, что неупорядоченная карта использует экземпляр std::hash, но его специализация для класса Identifier имеет удаленный operator().Теперь у вас есть два варианта:

  1. специализировать std::hash для вашего типа:

    namespace std
    {
    template<>
    class hash
    {
    public:
    std::size_t operator()(Identifier const&) const
    {
        return /* whatever is appropriate */;
        // best is if you can base the hash code on already defined
        // hashes of its members
    }
    };
    }
  2. написать свой собственный класс хеша (снова предоставляя operator()) и укажите его в качестве третьего параметра шаблона для неупорядоченной карты: std::unordered_map<Identifier, String, MyHash>

1 голос
/ 22 мая 2019

Я смог создать собственный хеш для этого класса, взглянув на его реализацию, его возвращаемые типы и возвращаемые типы возвращаемых типов, пока не нашел эффективную серию методов, которая возвращает стандартный тип, который я мог бы вернуть * 1001. * имеет специализацию по типу. Список находится здесь: http://www.cplusplus.com/reference/functional/hash/

struct IdentifierHash {
    size_t operator()(const juce::Identifier& v) const
    {
        std::hash<char*> hash;
        return hash(v.getCharPointer().getAddress());
    }
};

typedef std::unordered_map<Identifier, String, IdentifierHash> IdentifierMap;

Если я хочу использовать std::map, тогда я могу создать компаратор, подобный этому:

struct IdentifierComparator
{
    bool operator()(const Identifier& left, const Identifier& right) const
    {
        return left.getCharPointer().getAddress() < right.getCharPointer().getAddress();
    }
};

typedef std::map<Identifier, String, IdentifierComparator> IdentifierMap;
0 голосов
/ 22 мая 2019

Назовите параметры ваших бинарных операторов lho и tho (левый операнд и правый операнд), это сразу даст понять, что вы ожидаете вернуть. (Верно в случае lho https://en.cppreference.com/w/cpp/named_req/Compare

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

M2C

...