Карта уникальных указателей, .at () с необработанным указателем - PullRequest
1 голос
/ 16 мая 2019

Скажем, у меня есть карта:

std::map<std::unique_ptr<SomeType>, SomeOtherType> map;

Очевидно, это не сработает, потому что ключевое значение нашей карты - это уникальный ptr, а не необработанный:

//a pointer from somewhere else in the code
SomeType* p = ...;
auto result {map.at(p)};

Вместо этого можно сделать что-то вроде этого, используя std :: unique_ptr.get ():

SomeType* p = ...;
for(auto& entry : map) {
    if(entry.first.get() == p) {
        //do whatever
    }
}

Однако это очень уродливый и, возможно, неэффективный способ.У меня вопрос просто: есть ли способ использовать функцию .at () в этом случае?

1 Ответ

6 голосов
/ 16 мая 2019

В C ++ 14 вы можете предоставить прозрачный компаратор

template<typename T>
struct PtrCompare
{
    std::less<T*> less;
    using is_transparent = void;
    bool operator()(T* lhs, const std::unique_ptr<T> & rhs) const { return less(lhs, rhs.get()); }
    bool operator()(const std::unique_ptr<T> & lhs, T* rhs) const { return less(lhs.get(), rhs); }
    bool operator()(const std::unique_ptr<T> & lhs, const std::unique_ptr<T> & rhs) const { return less(lhs.get(), rhs.get()); }
}

std::map<std::unique_ptr<SomeType>, SomeOtherType, PtrCompare<SomeType>> map;

Это не помогает с at, но позволяет вам find на основе всего, что вы можете сравнить

SomeType* p = ...;
if (auto it = map.find(p))
{
    // use it->second
}
else
{
    throw std::out_of_range;
}
...