假设我想做一些像这样做的事情:
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>
但是根据我的理解,例如deque
和vector
具有相似的界面。第一个重载将接受deque
,forward_list
和vector
。所以我的问题是,是否有一个简单的列表或图表可以告诉我需要多少重载?
答案 0 :(得分:2)
标准序列容器在第23.3.1节中列举[sequences.general] / 1:
标题
<array>
,<deque>
,<forward_list>
,<list>
和<vector>
定义了满足序列容器要求的模板类。
那就是说,我更喜欢使用特征来检测类似序列和类似堆栈的类型的通用解决方案。我会将具有成员begin
和end
的序列称为任何返回相同类型的序列:
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));
我们会说成员top
,pop
和empty() 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;
}