Kafka
Kafka

Reputation: 810

unable to get key_type from a map

I wrote this piece of code in order to check if a std::map contains a specific key:

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

I have the following error:

error: key_type is not a member of const std::map<std::__cxx11::basic_string<char>, Query>&

What is the problem with decltype(map)::key_type?

Upvotes: 10

Views: 940

Answers (2)

Elliott
Elliott

Reputation: 2623

The earlier answer explained the reason for the error, which does answer the question, but I wanted to expand on the solution to the problem:


Instead of converting the value back into its type to get the key_type, you can grab it from the type directly:

template <class T, class ... Args >
inline bool contains(const std::map<Args...>& map, const T& value) noexcept
{
    using Key = typename std::map<Args...>::key_type;

    static_assert(std::is_constructible_v<Key, T>);

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

demo (Note that the code in the question uses C++17 syntax, despite the C++11 tag)


But I think a better solution is to name the appropriate template type:

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

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

demo

Upvotes: 0

Holt
Holt

Reputation: 37606

The error is quite explicit, decltype(map) is const std::map<Args... >&, which is a const-reference to a std::map. Since it's a reference type, it does not have a ::key_type.

You need to use std::remove_reference_t to drop the reference:

static_assert(std::is_constructible_v<
    typename std::remove_reference_t<decltype(map)>::key_type,
    T 
>);

You need the typename because std::remove_reference_t<decltype(map)> is a dependent name.

A more idiomatic way would be to use a Map template parameter and not constrain the function to 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);
}

Upvotes: 10

Related Questions