如何制作一个接受地图或unordered_map的函数

How can I make a function that takes either a map or an unordered_map?

本文关键字:unordered 地图 map 函数 何制作 一个      更新时间:2023-10-16

我正在实现一些基于模板的序列化。我实现了std::map的模板化功能,但现在我使用的是std::unordered_map。我宁愿不复制和粘贴整个函数,而只是更改参数类型。有没有办法制作一个只需要地图或无序地图的模板?

template <typename MAP>
void generic_foo(MAP& map)
{
    // generic implementation of your function
    // that works with unordered_map and map
    using K = typename MAP::key_type;
    using T = typename MAP::mapped_type;
}
// matches any possible implementation of std::unorderd_map
template <class Key,                                    
          class T,                                   
          class Hash,                       
          class Pred,                  
          class Alloc>
void foo(std::unordered_map<Key, T, Hash, Pred, Alloc>& m)
{
    // signature matched! forward to your implementation
    generic_foo(m);
}
// matches any possible implementation of std::map        
template <class Key,                                    
          class T,                          
          class Compare,                  
          class Alloc>
void foo(std::map<Key, T, Compare, Alloc>& m)
{
    // signature matched! forward to your implementation
    generic_foo(m);
} 

现场演示

只需将函数重载为非模板化函数,一个重载采用std::map,另一个重载取std::unordered_map。 让这两个函数调用一个隐藏的template,该接受任何内容,但只能由它们调用。 一种方法是将其隐藏在匿名namespace中。

具有 C++20 个概念

要支持特定的std::mapstd::unordered_map

template<typename T> struct is_unordered_map
   : public std::false_type {};
template<typename... Args>
struct is_unordered_map<std::unordered_map<Args...>>
   : public std::true_type {};
template<typename T> struct is_map
   : public std::false_type {};
template<typename... Args>
struct is_map<std::map<Args...>>
   : public std::true_type {};
template<typename C>
concept UnorderedMap = is_unordered_map<C>::value;
template<typename C>
concept Map = is_map<C>::value;
template<typename C>
concept MappingContainer =
    Map<C> || UnorderedMap<C>;
void foo(const MappingContainer auto& m) { ... }

代码:https://godbolt.org/z/MrsaGn

<小时 />

若要支持任何充当映射类型的类型,请执行以下操作:

template<typename C>
concept MappingContainer = requires(C c) {
    typename C::key_type;
    typename C::mapped_type;
    typename C::value_type;
    typename C::iterator;
    requires std::same_as<decltype(c.begin()), typename C::iterator>;
    requires std::same_as<decltype(c.end()), typename C::iterator>;
    requires std::same_as<
        typename C::value_type,
        std::iter_value_t<typename C::iterator>
    >;
    requires std::same_as<
        typename C::value_type,
        std::pair<const typename C::key_type, typename C::mapped_type>
    >;
};
void foo(const MappingContainer auto& m) { ... }

代码:https://godbolt.org/z/jPfMhT

#include<type_traits>
template<typename T>
void foo(T t){
    static_assert(std::is_same<T, std::map</*some_type*/>::value
               || std::is_same<T, std::unordered_map</*some_type*/>::value,
                  "Foo can only get std::map or std::unordered_map.");
}
下面是

一个从std::mapstd::unordered_map中提取键/值的示例

template <typename M>
std::unordered_set<typename M::key_type> GetMapKeys(const M& a_map) {
  std::unordered_set<typename M::key_type> keys;
  for (auto const& e : a_map) {
    keys.emplace(e.first);
  }
  return keys;
}
template <typename M>
std::vector<typename M::mapped_type> GetMapValues(const M& a_map) {
  std::vector<typename M::mapped_type> values;
  values.reserve(a_map.size());
  for (auto const& e : a_map) {
    values.push_back(e.second);
  }
  return values;
}