专门用于可转换为指针的迭代器的类

时间:2012-03-21 04:42:51

标签: c++ templates stl containers specialization

我正在尝试开发一个类,它允许我在正确完成时通过迭代器语义有效地访问容器/指针,并且当迭代器无法转换为指针时我想将迭代器范围复制到临时缓冲并返回该指针。为此,我编写了以下程序:

#include <cassert>
#include <vector>
#include <deque>
#include <list>

// General case copies data to temporary vector, in case iterators are from a list or otherwise.
template < typename Iterator, typename tag = std::iterator_traits < Iterator >::iterator_category >
class IteratorBuffer
{
    typedef typename std::iterator_traits < Iterator >::value_type T;

    std::vector < T > temp;
public:
    IteratorBuffer(Iterator begin, Iterator end) : temp(std::distance(begin, end)) 
    { 
        std::copy(begin, end, temp.begin()); 
    } 

    const T * data() { return temp.data(); }
};

// Special case should be invoked if Iterator can safely be treated as a pointer to the range.
template < typename Iterator >
class IteratorBuffer < Iterator, std::random_access_iterator_tag >
{
    typedef typename std::iterator_traits < Iterator >::value_type T;

    const T * temp;
public:
    IteratorBuffer(Iterator begin, Iterator end) : temp(&*begin) { }

    const T * data() { return temp; }
};

int main(int argc, char ** argv)
{
    std::vector < int > test1(10);
    IteratorBuffer < std::vector < int >::iterator > temp1(test1.begin(), test1.end());
    // This should be pointing to the data in test1.
    assert(temp1.data() == test1.data());

    std::list < int > test2;
    for(int i = 0; i < 10; ++i)
        test2.push_back(i);
    IteratorBuffer < std::list < int >::iterator > temp2(test2.begin(), test2.end());
    // This must not point to the beginning iterator.
    assert(temp2.data() != &*test2.begin());

    int test3[10];
    IteratorBuffer < int * > temp3(&test3[0], &test3[10]);
    // This should point to the array.
    assert(temp3.data() == &test3[0]);

    std::deque < int > test4;
    for(int i = 0; i < 10; ++i)
        test4.push_back(i);
    IteratorBuffer < std::deque < int >::iterator > temp4(test4.begin(), test4.end());
    // This must not point to the beginning iterator, not safe.
    assert(temp4.data() != &*test4.begin());
}

这导致上一次测试失败,因为std :: deque的迭代器有random_access_iterator_tag。

如何编写此类以使其一般正常工作?

我想我应该提一下我正在使用VC ++ 2010。

编辑:正如亚当所说(我害怕这一点),这不是直接可能的。现在,我试图定义自己的特征,这使我能够做到这一点。请参阅下面的尝试:

template < typename Iterator >
struct IteratorTraits 
{ 
    enum { IsPointerCompatible = false }; 
    typedef typename std::iterator_traits < Iterator >::value_type T;
};
template < typename T >
struct IteratorTraits < T * > 
{ 
    enum { IsPointerCompatible = true }; 
    typedef T T;
};
template < typename T >
struct IteratorTraits < const T * > 
{ 
    enum { IsPointerCompatible = true }; 
    typedef const T T;
};
//template < typename T >
//struct IteratorTraits < typename std::vector < T >::iterator > 
//{ 
//  enum { IsPointerCompatible = true };
//  typedef T T;
//};
//template < typename T, size_t N >
//struct IteratorTraits < typename std::array < T, N >::iterator > 
//{ 
//  enum { IsPointerCompatible = true };
//  typedef T T;
//};

我省略了IteratorBuffer类,因为它们与使用std :: iterator_traits的类非常相似。

前两个专业有效,但两个评论的特征结构不起作用。如何编写这些文件以使其可以工作,而不依赖于我特定的STL实现?

1 个答案:

答案 0 :(得分:1)

您可以显式地专门指定指针,然后可以为任何容器(您知道)专门处理哪些迭代器可以这样处理(std::vector就是这种情况)。这并不是那么糟糕,因为没有容器的一般“特征”可以说它的迭代器可以用作指针。这是容器提供商必须明确做出的保证。


另请注意,IteratorBuffer的通用版本默认至少采用前向迭代器类别,并且将使用仅输入迭代器失败(因为它使用两次范围)。