标准库中有多少个不同的类模板排列?

时间:2014-02-15 23:14:00

标签: c++ c++11 stl

假设我想做一些像这样做的事情:

template<typename T, template <typename, typename> class Cont>
std::ostream& operator<<(std::ostream& os, Cont<T, std::allocator<T>> cont)
{
    for (const auto& el : cont)
        std::cout << el << "\n";
    return os;
}

template<typename T, template <typename, typename> class Cont>
std::ostream& operator<<(std::ostream& os, Cont<T, std::deque<T>> cont)
{
    while (!cont.empty())
    {
        std::cout << cont.top() << "\n";
        cont.pop();
    }
    return os;
}

我意识到我可以std::vector<T>std::stack<T>但是根据我的理解,例如dequevector具有相似的界面。第一个重载将接受dequeforward_listvector。所以我的问题是,是否有一个简单的列表或图表可以告诉我需要多少重载?

1 个答案:

答案 0 :(得分:2)

标准序列容器在第23.3.1节中列举[sequences.general] / 1:

  

标题<array><deque><forward_list><list><vector>定义了满足序列容器要求的模板类。

那就是说,我更喜欢使用特征来检测类似序列和类似堆栈的类型的通用解决方案。我会将具有成员beginend的序列称为任何返回相同类型的序列:

template <bool B, typename T>
using enable_if =
  typename std::enable_if<B, T>::type;

template <typename T>
struct is_sequence_helper {
  template <typename U=T>
  static auto test(int) ->
    enable_if<
      std::is_same<
        decltype(std::declval<U>().begin()),
        decltype(std::declval<U>().end())
      >::value,
      std::true_type
    >;

  template <typename U=T>
  static auto test(...) -> std::false_type;
};

template <typename T>
using is_sequence =
  decltype(is_sequence_helper<T>::test(0));

我们会说成员toppopempty() const是一个堆栈:

template <typename T>
struct is_stack_helper {
  template <typename U=T>
  static auto test(int) ->
    decltype((std::declval<U>().top(),
              std::declval<U>().pop(),
              std::declval<const U>().empty(),
              std::true_type{}));

  template <typename U=T>
  static auto test(...) -> std::false_type;
};
template <typename T>
using is_stack =
  decltype(is_stack_helper<T>::test(0));

有了这些特性,我们可以更加一般地限制你的流插入操作符来处理序列或堆栈:

template<typename Sequence>
enable_if<
  is_sequence<Sequence>::value && !is_stack<Sequence>::value,
  std::ostream&
> operator<<(std::ostream& os, const Sequence& cont) {
  os << "sequence version:\n";
  for (const auto& el : cont)
    os << el << '\n';
  return os;
}

template<typename Stack>
enable_if<
  is_stack<Stack>::value,
  std::ostream&
> operator<<(std::ostream& os, Stack& cont) {
  os << "stack version:\n";
  for (; !cont.empty(); cont.pop())
    os << cont.top() << '\n';
  return os;
}

See it all pulled together and working at Coliru