检查类型是否为地图

时间:2016-02-09 13:35:27

标签: c++ dictionary c++14 typetraits

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

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

执行此标记调度的安全,干净的方法是什么?

3 个答案:

答案 0 :(得分:13)

现有答案测试std::map的非常具体的属性,或者它恰好是std::map的特化(对于std::unordered_map是假的,或者对于std::map是非标准的类型接口为value_type),或测试其std::pair<const key_type, mapped_type>是否为multimap(对于unordered_mapkey_type都是如此,但对于非标准类型则为false有类似的接口)。

这仅测试它提供mapped_typeoperator[]成员,并且可以使用std::multimap进行访问,因此不会说#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 { }; 是mappish:

is_mappish

由于true_type具有false_typetemplate <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

或者你可以完全避免调度,只是为地图和非地图重载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 }

/bank/accounts
/bank/accounts/{guid}
/customers/{guid}/

答案 1 :(得分: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
}

答案 2 :(得分:1)

这是我想出的:

#include <type_traits>
#include <utility>

namespace detail
{
    template <typename T, typename = void>
    struct IsMap : std::false_type {};

    template <typename T>
    struct IsMap<T, std::enable_if_t<
                        std::is_same<typename T::value_type,
                                    std::pair<const typename T::key_type,
                                              typename T::mapped_type>
                        >::value>
    > : std::true_type {};
}

template <typename T>
constexpr bool is_map = detail::IsMap<T>::value;

namespace { template <bool> struct MapTagImpl {}; }
using MapTag    = MapTagImpl<true>;
using NonMapTag = MapTagImpl<false>;

template <typename T>
using MapTagType = MapTagImpl<is_map<T>>;