无法从映射中获取键类型

9

我写了这段代码来检查一个 std::map 是否包含特定的键:

template<typename T, typename... Args >
inline bool contains(const std::map<Args...>& map, const T& value) noexcept
{
  static_assert(std::is_constructible_v< decltype(map)::key_type , T >);

  return map.find(value) != std::end(map);
}

我遇到了以下错误:
``` error: key_type is not a member of const std::map, Query>& ```
`decltype(map)::key_type` 的问题在哪里?
1个回答

10
错误信息很明确,decltype(map)是一个const std::map<Args... >&类型的常量引用,它是对std::map的一个常量引用。由于它是一个引用类型,因此它没有::key_type
您需要使用std::remove_reference_t来去除引用:
static_assert(std::is_constructible_v<
    typename std::remove_reference_t<decltype(map)>::key_type,
    T 
>);

你需要使用typename,因为std::remove_reference_t<decltype(map)>是一个依赖名称。

更加惯用的方式是使用Map模板参数,而不是将函数限制在std::map上:

template<typename T, typename Map>
inline bool contains(const Map &map, const T& value) noexcept {
  static_assert(std::is_constructible_v< typename Map::key_type , T >);
  return map.find(value) != std::end(map);
}

好的,我不知道引用类型没有 ::key_type(或其他容器的 value_type)。 谢谢。第二种方法似乎很有趣,但与我为其他容器编写的包含函数冲突(例如 std::array 没有 .find() 方法),所以我选择在函数中明确使用 std::map。 - Kafka
1
std::is_constructible_v<typename std::map<Args...>::key_type, T> 也可以工作(即我们已经有了地图类型!),但是您的建议更好。 - Lightness Races in Orbit
@Kafka 你可以通过使用SFINAE来禁用这种过载,方法是检查容器Map是否确实具有::key_type。你也可以使用std::find创建一个通用版本,但不幸的是,对于集合或映射上的std::find的复杂度没有任何保证... - Holt
@Kafka 这里有一个使用SFINAE和一个小特性来检查一个类型是否为关联容器(set / map 及其 unordered_ 版本)的可能版本:https://godbolt.org/z/7uXSpU。由于这与问题有些远离,因此没有在答案中包含它。 - Holt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接