为可转换为指针的迭代器专门化一个类

Specializing a class for iterators convertable to pointers

本文关键字:一个 专门化 可转换 指针 迭代器      更新时间:2023-10-16

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

#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实现的情况下编写这些代码,使其能够工作?

您可以显式地专门化指针,然后专门化任何容器(您所知道的),可以以这种方式处理迭代器(std::vector就是这样)。这并没有那么糟糕,因为容器没有通用的"特性",即它的迭代器可以用作指针。这是容器提供者必须明确作出的保证。


还要注意的是,IteratorBuffer的通用版本至少默认为前向迭代器类别,并且在使用仅输入迭代器时会失败(因为它使用了两次范围)。