101*_*010 12 c++ iterator stl c++03
假设我有一个C容器(例如MyContainer),其中包含的对象存储为void*指针.迭代此容器元素的唯一方法是通过两个接口函数:
getFirstElem(MyContainer const&, void*):输出容器的第一个元素.getNextElem(MyContainer const&, void*):输出容器的下一个元素.我想编写一个泛型函数,它通过上面提到的接口函数遍历这个C容器的元素,并将它们的值复制到C++容器中(例如std::vector).
到目前为止我做了什么:
template<typename OutputIterator>
void
copy_container(MyContainer const &cont, OutputIterator first) {
typename std::iterator_traits<OutputIterator>::value_type elem;
if(getFirstElem(cont, &elem)) {
do {
*first = elem;
++first;
} while(getNextElem(cont, &elem))
}
}
Run Code Online (Sandbox Code Playgroud)
上面的示例适用于普通迭代器.但是,它无法使用输出迭代器进行编译(例如,copy_container(cont, std::back_inserter(myvector));).
原因是在参数类型是输出迭代器的情况下std::iterator_traits::value_type导致结果void.
有没有办法让这个泛型函数也适用于输出迭代器?
我知道在C++ 11中它可以通过使用decltype(例如decltype(*first))来完成,但我对C++ 11之前的解决方案特别感兴趣,因为我使用旧的C++编译器(gcc v4.4.7).
正确观察,value_type输出迭代器是void.除了替换这个之外没什么可做的:
typename std::iterator_traits<OutputIterator>::value_type elem;
Run Code Online (Sandbox Code Playgroud)
有了这个
decltype(*first) elem;
Run Code Online (Sandbox Code Playgroud)
(即使标准不保证它可以工作 - 可以通过取消引用输出迭代器来返回代理).
正如您所说,没有C++ 11解决方案,因此可能需要进行重新设计.以下是一些选项:
您可以将引用传递给容器,而不是第一个元素的迭代器.看起来你想要的只是一个push_back.
template<template<typename,typename> class stlContainer>
void copy_container(
MyMontainer const &cont, OutputIterator first)
{
// insertion in stlContainer
Run Code Online (Sandbox Code Playgroud)
那么你所需要的只是一层特征,可以调度到每个容器的正确插入实现
值类型可以是额外的模板参数.
template<typename value_type, typename OutputIterator>
void copy_container(MyMontainer const &cont, OutputIterator first)
{
value_type elem;
...
Run Code Online (Sandbox Code Playgroud)
您可以使用 typetraits 和专业化
template <typename IT>
struct it_value_type
{
typedef typename std::iterator_traits<IT>::value_type elem;
};
template <typename Container>
struct it_value_type<std::back_insert_iterator<Container>>
{
typedef typename Container::value_type elem;
};
template <typename Container>
struct it_value_type<std::front_insert_iterator<Container>>
{
typedef typename Container::value_type elem;
};
Run Code Online (Sandbox Code Playgroud)
然后你的代码变成:
template<typename OutputIterator>
void
copy_container(MyContainer const &cont, OutputIterator first) {
typename it_value_type<OutputIterator>::elem elem;
if (getFirstElem(cont, &elem)) {
do {
*first = elem;
++first;
} while (getNextElem(cont, &elem));
}
}
Run Code Online (Sandbox Code Playgroud)