检查类型是否为地图 [英] Checking if a type is a map

查看:104
本文介绍了检查类型是否为地图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时我发现有必要编写可应用于对象容器或此类容器的映射的通用例程(即处理映射中的每个容器).一种方法是为地图类型编写单独的例程,但是我认为拥有一个对两种类型的输入都适用的例程会更自然,更省时间:

I sometimes find the need to write general routines that can be applied to a container of objects, or a map of such containers (i.e. process each container in the map). One approach is to write separate routines for map types, but I think it can be more natural and less verbose to have one routine that works for both types of input:

template <typename T>
auto foo(const T& items)
{ 
    return foo(items, /* tag dispatch to map or non-map */);
}

什么是安全,干净的方法来分发此标签?

What is a safe, clean way to do this tag dispatch?

推荐答案

现有答案测试std::map的非常特殊的属性,或者恰恰是std::map的特化(对于std::unordered_map而言,这是错误的)或与std::map具有相同接口的非标准类型),或测试其value_type恰好是std::pair<const key_type, mapped_type>(对于multimapunordered_map都是正确的,但对于具有相似特征的非标准类型则为false接口).

The existing answers test for very specific properties of std::map, either that it is precisely a specialization of std::map (which would be false for std::unordered_map or non-standard types with the same interface as std::map), or testing that its value_type is exactly std::pair<const key_type, mapped_type> (which would be true for multimap and unordered_map, but false for non-standard types with similar interfaces).

这仅测试它是否提供key_typemapped_type成员,并且可以使用operator[]进行访问,因此不说std::multimap是mappish:

This only tests that it provides key_type and mapped_type members, and can be accessed with operator[], so doesn't say that std::multimap is mappish:

#include <type_traits>

namespace detail {
  // Needed for some older versions of GCC
  template<typename...>
    struct voider { using type = void; };

  // std::void_t will be part of C++17, but until then define it ourselves:
  template<typename... T>
    using void_t = typename voider<T...>::type;

  template<typename T, typename U = void>
    struct is_mappish_impl : std::false_type { };

  template<typename T>
    struct is_mappish_impl<T, void_t<typename T::key_type,
                                     typename T::mapped_type,
                                     decltype(std::declval<T&>()[std::declval<const typename T::key_type&>()])>>
    : std::true_type { };
}

template<typename T>
struct is_mappish : detail::is_mappish_impl<T>::type { };

由于is_mappish具有true_typefalse_type的基本特征",因此可以像这样对它进行调度:

Because is_mappish has a "base characteristic" of either true_type or false_type you can dispatch on it like so:

template <typename T>
auto foo(const T& items, true_type)
{
    // here be maps
}

template <typename T>
auto foo(const T& items, false_type)
{
    // map-free zone
}

template <typename T>
auto foo(const T& items)
{ 
    return foo(items, is_mappish<T>{});
}

或者您可以避免完全调度,而只需对地图和非地图重载foo即可:

Or you can avoid dispatching entirely, and just overload foo for maps and non-maps:

template <typename T,
          std::enable_if_t<is_mappish<T>{}, int> = 0>
auto foo(const T& items)
{
    // here be maps
}

template <typename T,
          std::enable_if_t<!is_mappish<T>{}, int> = 0>
auto foo(const T& items)
{
    // map-free zone
}

这篇关于检查类型是否为地图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆