Search code examples
c++functor

Why can't I return a normal map reference with a transparent functor?


This code works:

class MyObj {};

class MyData {
 public:
  using tMyMap = std::map<uint64_t, std::shared_ptr<MyObj>>;

  const tMyMap& get_normal() const;
  const tMyMap& get_reverse() const;

 private:
  std::map<uint64_t, std::shared_ptr<MyObj>> _normal;

  std::map<uint64_t, std::shared_ptr<MyObj>, std::less<uint64_t>> _reverse;
};

const MyData::tMyMap& get_normal() const { return _normal; }
const MyData::tMyMap& get_reverse() const { return _reverse; }

But clang-tidy recommends that I use a transparent functor and change std::less<uint64_t> to std::less<> in my declaration of _reverse. Unfortunately, when I do that, the code doesn't compile anymore:

test_map.cpp: In member function ‘const tMyMap& MyData::get_reverse() const’:
test_map.cpp:20:60: error: invalid initialization of reference of type ‘const tMyMap& {aka const std::map<long unsigned int, std::shared_ptr<MyObj> >&}’ from expression of type ‘const std::map<long unsigned int, std::shared_ptr<MyObj>, std::less<void> >’
 const MyData::tMyMap& MyData::get_reverse() const { return _reverse; }

That error message is from g++, but clang gives me a similar error.

Why is the typed functor okay, but the transparent functor doesn't compile?


Solution

  • std::map's default comparator is std::less<KeyType>.

    This means that

    std::map<uint64_t, T>
    

    and

    std::map<uint64_t, T, std::less<uint64_t>>
    

    are the same type, but

    std::map<uint64_t, T, std::less<>>
    

    is a different type because std::less<uint64_t> and std::less<> are different types.


    You would see the same issue if _normal and _reverse were actually the reverse of each other. I assume you actually meant to declare _reverse as

    std::map<uint64_t, std::shared_ptr<MyObj>, std::greater<uint64_t>> _reverse;
    

    so that it's ordered in the opposite direction from _normal.