【发布时间】:2012-03-21 04:42:51
【问题描述】:
我正在尝试开发一个类,当它可以正确完成时,我可以通过迭代器语义有效地访问容器/指针,并且当迭代器无法转换为指针时,我想将迭代器范围复制到临时缓冲并返回该指针。为此,我编写了以下程序:
#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 实现?
【问题讨论】:
-
&*test2.begin()看起来很丑! -
它很难看,但它可以工作......
-
恐怕这不太可能。唯一的可能性是专门针对特定的迭代器,例如
vector<T>::iterator。请注意,vector<T>::reverse_iterator不安全。 -
@n.m.感谢您的评论,请参阅我对特定迭代器类的专业化的编辑。
-
在您的专业化中,
Iterator未定义(主模板中的定义不在范围内)。您需要再次定义它:typedef typename std::vector <T>::iterator Iterator;。顺便说一句,typedef T T看起来有点奇怪,虽然不是不正确的 AFAICT。无论如何我都会使用不同的标识符。
标签: c++ templates stl containers specialization