Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking if a type is a map

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?

like image 642
Daniel Avatar asked Feb 09 '16 13:02

Daniel


People also ask

How do you check if an object is a map?

Use the instanceof operator to check if an object is a Map - myObj instanceof Map . The instanceof operator returns true if the prototype property of a constructor appears in the prototype chain of the object.

How do you check if a value is in a map JavaScript?

The Map.has() method in JavaScript is used to check whether an element with a specified key exists in a map or not. It returns a boolean value indicating the presence or absence of an element with a specified key in a map.

How do you check if an object has a key in JavaScript?

There are mainly two methods to check the existence of a key in JavaScript Object. The first one is using “in operator” and the second one is using “hasOwnProperty() method”. Method 1: Using 'in' operator: The in operator returns a boolean value if the specified property is in the object.

How do I create a map in TypeScript?

Creating a MapUse Map type and new keyword to create a map in TypeScript. let myMap = new Map<string, number>(); To create a Map with initial key-value pairs, pass the key-value pairs as an array to the Map constructor.


2 Answers

This has worked for me, not tested 100% though:

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
}
like image 167
David Haim Avatar answered Oct 17 '22 16:10

David Haim


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).

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

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

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
}
like image 21
Jonathan Wakely Avatar answered Oct 17 '22 16:10

Jonathan Wakely