为什么我不能 return 具有透明仿函数的法线贴图引用?
Why can't I return a normal map reference with a transparent 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 建议我使用透明仿函数,并在我的 _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::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;
};
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
相反。
此代码有效:
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::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;
};
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
相反。