为什么我的自定义迭代器不能与STL副本一起使用?

时间:2009-11-12 17:35:03

标签: c++ stl iterator

我为answer to another question编写了一个OutputIterator。这是:

#include <queue>

using namespace std;

template< typename T, typename U >
class queue_inserter {
    queue<T, U> &qu;  
public:
    queue_inserter(queue<T,U> &q) : qu(q) { }
    queue_inserter<T,U> operator ++ (int) { return *this; }
    queue_inserter<T,U> operator * () { return *this; }
    void operator = (const T &val) { qu.push(val); }
};

template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q) {
    return queue_inserter<T,U>(q);
}    

这适用于这个小复制功能:

template<typename II, typename OI>
void mycopy(II b, II e, OI oi) {
    while (b != e) { *oi++ = *b++; }
}

但它对copy的STL algorithms根本不起作用。以下是我得到的精彩C ++错误:

i.cpp:33: error: specialization of ‘template<class _Iterator> struct std::iterator_traits’ in different namespace
/usr/include/c++/4.0.0/bits/stl_iterator_base_types.h:127: error:   from definition of ‘template<class _Iterator> struct std::iterator_traits’
/usr/include/c++/4.0.0/bits/stl_algobase.h: In function ‘_OI std::__copy_aux(_II, _II, _OI) [with _II = int*, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’:
/usr/include/c++/4.0.0/bits/stl_algobase.h:335:   instantiated from ‘static _OI std::__copy_normal<true, false>::copy_n(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
/usr/include/c++/4.0.0/bits/stl_algobase.h:387:   instantiated from ‘_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OutputIterator = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
i.cpp:53:   instantiated from here
/usr/include/c++/4.0.0/bits/stl_algobase.h:310: error: no type named ‘value_type’ in ‘struct std::iterator_traits<queue_inserter<int, std::deque<int, std::allocator<int> > > >’
/usr/include/c++/4.0.0/bits/stl_algobase.h:315: error: no type named ‘value_type’ in ‘struct std::iterator_traits<queue_inserter<int, std::deque<int, std::allocator<int> > > >’
/usr/include/c++/4.0.0/bits/stl_algobase.h:315: error: ‘__value’ is not a member of ‘<declaration error>’
/usr/include/c++/4.0.0/bits/stl_algobase.h:335:   instantiated from ‘static _OI std::__copy_normal<true, false>::copy_n(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
/usr/include/c++/4.0.0/bits/stl_algobase.h:387:   instantiated from ‘_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OutputIterator = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
i.cpp:53:   instantiated from here
/usr/include/c++/4.0.0/bits/stl_algobase.h:317: error: ‘__simple’ is not a valid template argument for type ‘bool’ because it is a non-constant expression
/usr/include/c++/4.0.0/bits/stl_algobase.h:317: error: ‘copy’ is not a member of ‘<declaration error>’

这是驱动程序:

int main() {
    vector<int> v;
    v.push_back( 1 );
    v.push_back( 2 );
    queue<int> q;
    copy( v.begin(), v.end(), make_queue_inserter(q) );
    while (q.size() > 0) {
        cout << q.front() << endl;
        q.pop();
    }
}

为什么世界上它是专门的iterator_traits。我的迭代器出了什么问题?我不能只编写自己的简单迭代器吗?

4 个答案:

答案 0 :(得分:17)

您的queue_inserter需要从std::iterator派生,以便正确定义所有typedef,例如value_type,因为这些在STL算法中使用,这个定义有效:

template< typename T, typename U >
class queue_inserter : public std::iterator<std::output_iterator_tag, T>{
    queue<T, U> &qu;  
public:
    queue_inserter(queue<T,U> &q) : qu(q) { }
    queue_inserter<T,U> operator ++ (int) { return *this; }
    queue_inserter<T,U> operator ++ () { return *this; }
    queue_inserter<T,U> operator * () { return *this; }
    void operator = (const T &val) { qu.push(val); }
};

答案 1 :(得分:8)

从std :: iterator中导出它。如果您有兴趣,Dobb博士有一个关于自定义容器和迭代器的article

答案 2 :(得分:6)

你的迭代器不符合'assignable'类型的要求,这是输出迭代器的一个要求,因为它包含一个引用,并且可分配的类型需要确保在t = utu相当于iterator_traits

您可以通过派生std::iterator的特化或明确提供一个来为您的迭代器提供namespace std { template<> struct iterator_traits<MyIterator> { typedef std::output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; }; } 的合适专业化。

{{1}}

答案 3 :(得分:4)

#include <queue>
#include <algorithm>
#include <iterator>
#include <iostream>

using namespace std;

template< typename T, typename U >
class queue_inserter
{
    queue<T, U> &qu;

public:
    // for iterator_traits to refer
    typedef output_iterator_tag iterator_category;
    typedef T value_type;
    typedef ptrdiff_t difference_type;
    typedef T* pointer;
    typedef T& reference;

    queue_inserter(queue<T,U> &q) : qu(q) { }
    queue_inserter<T,U>& operator ++ () { return *this; }
    queue_inserter<T,U> operator * () { return *this; }
    void operator = (const T &val) { qu.push(val); }
};

template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q)
{
    return queue_inserter<T,U>(q);
}

int main()
{
    // uses initalizer list (C++0x), pass -std=c++0x to g++
    vector<int> v({1, 2, 3});
    queue<int, deque<int>> q;
    copy(v.cbegin(), v.cend(), make_queue_inserter(q));
    while (!q.empty())
    {
        cout << q.front() << endl;
        q.pop();
    }
}

这应该与iterator_traits一起做; <iterator>中的辅助结构,它定义了迭代器通常应定义的所有类型。 <algorithm>中的函数,在需要时引用这些类型,如iterator_traits<it>::iterator_category或说iterator_traits<it>::value_type等。只需在一个自定义迭代器中定义它们就可以了。这是编写迭代器的现代方法,而不是从std::iterator继承的传统方式。看一下<iterator>就会发现偶数std::iterator定义了这些类型,即iterator_category,difference_type等。这就是从std::iterator继承的原因,派生的迭代器类由于遗传而得到这些