为什么不能使用透明函子返回法线贴图参考?

时间:2018-09-22 22:30:28

标签: c++ functor

此代码有效:

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; }

但是clang-tidy建议我使用透明函子,并在声明std::less<uint64_t>中将std::less<>更改为_reverse。不幸的是,当我这样做时,代码不再编译了:

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; }

该错误消息来自g ++,但是clang给了我类似的错误。

为什么键入的函子可以,但是透明函子不能编译?

2 个答案:

答案 0 :(得分:2)

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.

答案 1 :(得分:1)

The problem is that the comparison function is part of the type of an instance of the std::map template. The default value for the comparison function used by an std::map<K, T> is std::less<T>. So

std::map<uint64_t, std::shared_ptr<MyObj>, std::less<uint64_t>>

and

std::map<uint64_t, std::shared_ptr<MyObj>>

happen to be the same type (the second version will use the default argument for the comparison function, which comes out to be std::less<uint64_t>). However, if you use std::less<> (which is equivalent to std::less<void>) as your comparison function for _reverse, then the types of _normal and _reverse will not turn out the same anymore. Only _normal will still be of type tMyMap, which uses the default comparison function, while _reverse will be a different, unrelated type.

If the purpose of MyData is simply to hold these two maps, you might want to consider just turning it into a struct:

struct MyData {
  std::map<uint64_t, std::shared_ptr<MyObj>> normal;
  std::map<uint64_t, std::shared_ptr<MyObj>, std::less<>> reverse;
};

Or just use auto to avoid having to repeat the type of each map

class MyData {
public:
  const auto& get_normal() const { return _normal; }
  const auto& get_reverse() const { return _reverse; }

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