【问题标题】:Is there a better way to check if a STL container is a multi* container有没有更好的方法来检查 STL 容器是否是多 * 容器
【发布时间】:2013-06-07 21:56:12
【问题描述】:

在我为一个可以与所有类型的标准 C++11 容器一起工作的框架编写单元测试的过程中,我遇到了我想以通用方式创建测试数据的问题。 在这里,我需要知道关联的容器 C 是否是 multi* 容器。例如。如果 C 是 std::set 或 std::multiset。我搜索了所有这些容器的界面,它们都有一个共同点,即它们都有一个 insert(value_type const&) 方法。但从我的角度来看,显着的区别在于 multi* 版本只返回一个迭代器,但“非”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。

【问题讨论】:

  • 这看起来不错!你说更优雅?
  • typename 之前的 decltype 不是必需的(我需要删除它才能在 gcc 上编译)。
  • prajmus, typeid().name() 是RTTI,有运行时开销,这是编译时测试。
  • 你不能在不解析的情况下使用 typeid().name() ,因为它可能是一个集合>(例如)
  • std::type_info::name() 返回一个实现定义的字符串,不保证它包含“multi”

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


【解决方案1】:

鉴于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

【讨论】:

  • 感谢您的回复!与您的想法相比,我有类似的想法。我看到了您的解决方案的优势,因为这些特征“说明”了它们的含义。但我一直在寻找一种更优雅、更易读、更短的解决方案。
  • @FelixPetriconi:更短并不意味着可读,棘手并不意味着优雅。完成后,您不会每天都盯着它看。把它塞进“is_multi_container.hpp”,再也不要看它了。
  • 不错。你能用类型列表解决重复问题吗?
  • 理论上,关联容器要求适用于比标准容器更多的类型,因此 OP 的解决方案更通用,可以与满足相同概念的第三方容器一起使用,例如来自 Boost.Container
  • @PeterWood:哪个重复? :)
猜你喜欢
  • 2011-05-12
  • 2013-03-13
  • 1970-01-01
  • 2012-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-28
相关资源
最近更新 更多