现有答案测试std::map 的非常具体的属性,或者它恰好是std::map 的特化(这对于std::unordered_map 或具有与std::map 相同接口的非标准类型是错误的) , 或者测试它的value_type 是否正好是std::pair<const key_type, mapped_type>(这对于multimap 和unordered_map 是正确的,但对于具有类似接口的非标准类型是错误的)。
这里只测试它提供key_type和mapped_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 { };
因为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>{});
}
或者您可以完全避免调度,而只为地图和非地图重载 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
}