检测类型是否为关联容器

时间:2014-03-03 20:41:15

标签: c++ templates containers sfinae

我正在编写一些容器操作函数。通常情况下,有一个版本用于类似矢量的容器,例如vector,list,deque,array等,另一个版本用于关联容器,如map,multimap,unordered_map等。我想知道什么是“最好的方法“检测一个类是否是一个关联容器。也许类似于使用mapped_type检测BOOST_MPL_HAS_XXX_TRAIT_DEF typedef的存在?

3 个答案:

答案 0 :(得分:1)

这是一个编译时测试,因此没有CPU /内存效率方面来选择“最佳方式”。如果你通过检查mapped_type并使用boost来满足你的需求,那么没有理由寻找任何不同的东西,尽管肯定有无助推的替代方案(例如参见here

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

答案 1 :(得分:1)

我不会那样做假设。要具体并专门化模板。

我这样做:

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

答案 2 :(得分:0)

我知道这个问题是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