有没有更好的方法来检查STL容器是否是一个多*容器

时间:2013-06-07 21:56:12

标签: c++ templates c++11 stl traits

在我为一个适用于各种标准C ++ 11容器的框架编写单元测试的工作中,我逐步解决了我想要以通用方式创建测试数据的问题。 在这里,我需要知道关联的容器C是否是多*容器。例如。如果C是std :: set或std :: multiset。我搜索了所有这些容器的接口,并且所有这些容器的共同之处在于它们具有insert(value_type const&)方法。但从我的观点来看,显着的区别是multi *版本只返回一个迭代器,但'non'multi *版本返回一个std :: pair。所以我选择这个作为区别。

我的结果代码是:

#include <type_traits>
#include <utility>

template <typename Container>
class is_multi_container
{
  typedef typename Container::value_type T;
  typedef typename Container::iterator ExpectedType;
  typedef decltype(Container().insert(T())) ResultType;
public:
  static const bool value = std::is_same<ResultType, ExpectedType>::value;
};

#include <iostream>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>

int main() {
  std::cout << "std::set<T> is " << is_multi_container<std::set<int>>::value << std::endl;
  std::cout << "std::multiset<T> is " << is_multi_container<std::multiset<int>>::value << std::endl;

  std::cout << "std::map<K,T> is " << is_multi_container<std::map<int,double>>::value << std::endl;
  std::cout << "std::multimap<K,T> is " << is_multi_container<std::multimap<int,double>>::value << std::endl;

  std::cout << "std::unordered_set<T> is " << is_multi_container<std::unordered_set<int>>::value << std::endl;
  std::cout << "std::unordered_multiset<T> is " << is_multi_container<std::unordered_multiset<int>>::value << std::endl;

  std::cout << "std::unordered_map<K,T> is " << is_multi_container<std::unordered_map<int,double>>::value << std::endl;
  std::cout << "std::unordered_multimap<K,T> is " << is_multi_container<std::unordered_multimap<int,double>>::value << std::endl;
}

根据这个小测试程序,它似乎有效,但我不确定a)这个解决方案是否有我目前没有看到的问题和b)是否有更优雅的方式来编写这样的特性?我知道该特征仅适用于关联容器。

非常感谢提前!

PS:我必须使用Visual Studio 2010。

1 个答案:

答案 0 :(得分:4)

看到有少量std::multi*个容器,你可以列出它们:

#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>

#include <type_traits>

template <typename Container>
struct is_multi_container :
    std::false_type
{};

template <typename T, typename Compare, typename Alloc>
struct is_multi_container<std::multiset<T, Compare, Alloc>> :
    std::true_type
{};

template <typename T, typename Compare, typename Alloc>
struct is_multi_container<std::multimap<T, Compare, Alloc>> :
    std::true_type
{};

template <typename T, typename Compare, typename Alloc>
struct is_multi_container<std::unordered_multiset<T, Compare, Alloc>> :
    std::true_type
{};

template <typename T, typename Compare, typename Alloc>
struct is_multi_container<std::unordered_multimap<T, Compare, Alloc>> :
    std::true_type
{};

更多代码行,但它易于阅读并且直接推理(即,它确实有效!)。

作为一个明确的清单,需要注意的是它不会自动扩展。为此,您的解决方案很好。 C ++ 14可能有AssociativeContainer概念,这会使这更容易;对此的研究留给读者练习。 ;)

示例:

#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::boolalpha;

    #define TEST(type, ...)                                     \
            std::cout << type " is: "                           \
                      << is_multi_container<__VA_ARGS__>::value \
                      << std::endl

    TEST("std::set<T>", std::set<int>);
    TEST("std::multiset<T>", std::multiset<int>);

    TEST("std::map<K,T>", std::map<int, double>);
    TEST("std::multimap<K,T>", std::multimap<int, double>);

    TEST("std::unordered_set<T>", std::unordered_set<int>);
    TEST("std::unordered_multiset<T>", std::unordered_multiset<int>);

    TEST("std::unordered_map<K,T>", std::unordered_map<int, double>);
    TEST("std::unordered_multimap<K,T>", std::unordered_multimap<int, double>);
}

输出:

std::set<T> is: false
std::multiset<T> is: true
std::map<K,T> is: false
std::multimap<K,T> is: true
std::unordered_set<T> is: false
std::unordered_multiset<T> is: true
std::unordered_map<K,T> is: false
std::unordered_multimap<K,T> is: true