检查类型是否为地图

Dan*_*iel 11 c++ dictionary type-traits c++14

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

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

什么是安全,干净的方式来执行此标签发送?

Jon*_*ely 13

现有的答案测试非常具体的属性std::map,要么是它的特殊化std::map(对于std::unordered_map具有相同接口的非标准类型是假的std::map),要么测试它value_type是否正确std::pair<const key_type, mapped_type>(对于multimapunordered_map,但对于具有类似接口的非标准类型,则为false).

这只测试它提供key_typemapped_type成员,并且可以访问operator[],所以不要说std::multimap是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 { };
Run Code Online (Sandbox Code Playgroud)

因为is_mappish有一个"基本特征" true_type或者false_type你可以像这样发送:

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>{});
}
Run Code Online (Sandbox Code Playgroud)

或者你可以完全避免调度,只是重载foo地图和非地图:

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
}
Run Code Online (Sandbox Code Playgroud)

  • @DavidHaim,显然是的.如果类型没有实现特定的接口,那么您可能不希望调度到依赖于该接口的模板函数.该特征可以很容易地定制,以检查地图界面的任何部分是否与OP的"foo"相关,该部分适用于地图,因为"地图"的任何定义与该功能相关. (2认同)

Dav*_*aim 10

这对我有用,但未经100%测试:

template <class T>
struct isMap {
    static constexpr bool value = false;
};

template<class Key,class Value>
struct isMap<std::map<Key,Value>> {
    static constexpr bool value = true;
};

int main() {
    constexpr bool b1 = isMap<int>::value; //false
    constexpr bool b2 = isMap<std::vector<int>>::value; //false
    constexpr bool b3 = isMap<std::map<int,std::string>>::value; //true
    constexpr bool b4 = isMap<std::future<int>>::value; //false
}
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,这仅适用于`std :: map`而不适用于其他'map'类型(例如`std :: unordered_map`).我应该在这个问题上更具体. (2认同)