检测类型是否为关联容器

Detect whether type is associative container

本文关键字:关联 类型 是否 检测      更新时间:2023-10-16

我正在编写一些容器操作函数。通常情况下,一个版本用于类似矢量的容器,如向量、列表、deque、数组等,而另一个版本用于关联容器,如map、multimap、unordered_map等。我想知道检测类是否为关联容器的"最佳方法"是什么。也许像用BOOST_MPL_HAS_XXX_TRAIT_DEF检测 mapped_type typedef 的存在?

这是一个编译时测试,因此没有CPU/内存效率方面来选择"最佳方法"。 如果您通过检查带有 boost 的mapped_type来使其工作,并且适合您的需求,则没有理由寻找任何不同的东西,尽管肯定有无提升的替代方案(例如,请参阅此处)

请注意,虽然setunordered_set被标准视为关联容器,但没有mapped_type成员 - 如果要包含它们,可以测试key_type

我不会走这种假设的方式。要具体并专门化模板。

我这样做:

// is_deque
// ========
template<typename T, typename ... Types>
struct is_deque {
    static constexpr bool value = false;
};

template<typename ... Types>
struct is_deque<std::deque<Types...>> {
    static constexpr bool value = true;
};

// is_forward_list
// ===============
template<typename T, typename ... Types>
struct is_forward_list {
    static constexpr bool value = false;
};

template<typename ... Types>
struct is_forward_list<std::forward_list<Types...>> {
    static constexpr bool value = true;
};

// list
// ====
template<typename T, typename ... Types>
struct is_list {
    static constexpr bool value = false;
};

template<typename ... Types>
struct is_list<std::list<Types...>> {
    static constexpr bool value = true;
};

// vector
// ======
template<typename T, typename ... Types>
struct is_vector {
    static constexpr bool value = false;
};

template<typename ... Types>
struct is_vector<std::vector<Types...>> {
    static constexpr bool value = true;
};

// map
// ===
template<typename T, typename ... Types>
struct is_map {
    static constexpr bool value = false;
};

template<typename ... Types>
struct is_map<std::map<Types...>> {
    static constexpr bool value = true;
};

// set
// ===
template<typename T, typename ... Types>
struct is_set {
    static constexpr bool value = false;
};

template<typename ... Types>
struct is_set<std::set<Types...>> {
    static constexpr bool value = true;
};

// unordered_map
// =============
template<typename T, typename ... Types>
struct is_unordered_map {
    static constexpr bool value = false;
};

template<typename ... Types>
struct is_unordered_map<std::unordered_map<Types...>> {
    static constexpr bool value = true;
};

// unordered_set
// =============
template<typename T, typename ... Types>
struct is_unordered_set {
    static constexpr bool value = false;
};

template<typename ... Types>
struct is_unordered_set<std::unordered_set<Types...>> {
    static constexpr bool value = true;
};

// is_sequence_container
// =====================
template <typename T>
struct is_sequence_container {
    static constexpr bool value
        =  is_deque<T>::value
        || is_forward_list<T>::value
        || is_list<T>::value
        || is_vector<T>::value;
};

// is_associative_container
// ========================
template <typename T>
struct is_associative_container {
    static constexpr bool value
        =  is_map<T>::value
        || is_set<T>::value;
};

// is_unordered_associative_container
// ==================================
template <typename T>
struct is_unordered_associative_container {
    static constexpr bool value
        =  is_unordered_map<T>::value
        || is_unordered_set<T>::value;
};

// is_container
// ============
template <typename T>
struct is_container {
    static constexpr bool value
        =  is_sequence_container<T>::value
        || is_associative_container<T>::value
        || is_unordered_associative_container<T>::value;
};
我知道

这个问题是在 5 年前提出的,但这是我所做的,没有任何超出c++11的要求:

/// @brief container traits
////////////////////////////////////////////////////////////////////////////////
namespace container_traits {
using tc = char[2];
template<typename T> struct is_container {
  static tc& test(...);
  template <typename U>
  static char test(U&&, decltype(std::begin(std::declval<U>()))* = 0);
  static constexpr bool value = sizeof(test(std::declval<T>())) == 1;
};
template < typename T > struct is_associative {
  static tc& test(...) ;
  template < typename U >
  static char test(U&&, typename U::key_type* = 0) ;
  static constexpr bool value = sizeof( test( std::declval<T>() ) ) == 1 ;
};
}
template < typename T > struct is_container :
  std::conditional<(container_traits::is_container<T>::value || std::is_array<T>::value)
                   && !std::is_same<T, std::string>::value
                   && !std::is_same<T, const std::string>::value, std::true_type, std::false_type >::type {};
template < typename T > struct is_associative :
  std::conditional< container_traits::is_container<T>::value && container_traits::is_associative<T>::value,  std::true_type, std::false_type >::type {};

////////////////////////////////////////////////////////////////////////////////
/// @brief no std::enable_if_t in c++11
////////////////////////////////////////////////////////////////////////////////
#if __cplusplus <= 201103L
namespace std {
template< bool B, class T = void >
using enable_if_t = typename std::enable_if<B,T>::type;
}
#endif