为什么我不能返回带有透明函子的法线映射引用?

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

本文关键字:映射 引用 不能 返回 透明 为什么      更新时间:2023-10-16

这段代码有效:

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

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给了我类似的错误。

为什么类型化函子没问题,但透明函子不编译?

std::map的默认比较器是std::less<KeyType>

这意味着

std::map<uint64_t, T>

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

是相同的类型,但

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

是一种不同的类型,因为std::less<uint64_t>std::less<>是不同的类型。


如果_normal_reverse实际上是相反的,您会看到同样的问题。 我假设你实际上打算宣布_reverse

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

以便它以与_normal相反的方向排序.

问题是比较函数是std::map模板实例类型的一部分。std::map<K, T>使用的比较函数的默认值为std::less<T>。所以

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

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

碰巧是相同的类型(第二个版本将使用比较函数的默认参数,结果是std::less<uint64_t>(。但是,如果您使用std::less<>(相当于std::less<void>(作为_reverse的比较函数,那么_normal_reverse的类型将不再相同。只有_normal仍然是tMyMap类型,它使用默认的比较函数,而_reverse将是不同的、不相关的类型。

如果MyData的目的只是为了保存这两个映射,则可能需要考虑将其转换为结构:

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

或者只是使用auto以避免重复每个地图的类型

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