2012-03-21 72 views
2

我正在嘗試開發一個類,它將允許我通過迭代器語義有效地訪問容器/指針,當它可以正確完成時,以及迭代器不能轉換爲我想要的指針時將迭代器範圍複製到臨時緩衝區,然後返回該指針。要做到這一點,我寫了下面的程序:專門針對可轉換爲指針的迭代器的類

#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 ::雙端隊列的迭代器有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; 
//}; 

,因爲它們非常類似於使用的std :: iterator_traits的那些我省略了IteratorBuffer類。

前兩個專業化工作,但兩個評論性狀結構不起作用。我如何編寫這些程序以使其能夠工作,而不依賴於特定的STL實現?

+0

'&* test2.begin()'看起來很醜! – iammilind 2012-03-21 04:55:56

+0

它的醜陋,但它的作品... – dsharlet 2012-03-21 05:01:20

+1

這恐怕不是真的可能。唯一的可能性是專門針對特定的迭代器,例如'vector :: iterator'。請注意'vector :: reverse_iterator'不安全。 – 2012-03-21 06:33:22

回答

1

你可以明確地指定指針,然後對任何容器(你知道)哪些迭代器可以這樣處理(這是std::vector的情況)。這並沒有那麼糟糕,因爲沒有一個容器的一般「特徵」可以說它的迭代器可以用作指針。這是容器供應商必須明確規定的保證。


還要注意的IteratorBuffer普通版默默地承擔至少前向迭代器類別,將只輸入迭代器失敗(因爲它使用範圍的兩倍)。

+0

感謝您的回答。看到我的編輯,我試圖實現你描述的內容,但是我很難理解如何爲特定的迭代器類定義特化。 – dsharlet 2012-03-21 16:20:58

+0

我試過了,我失敗了。相信沒有合理的標準兼容解決方案。但我會嘗試更多,如果我會找到任何我會在這裏發佈。 – 2012-03-22 12:49:32