2012-03-21 5 views
2

これは、イテレータを正確に実行できるとき、およびイテレータを必要なポインタに変換できないときに、コンテナ/ポインタに効率的にアクセスできるクラスを開発しようとしています。イテレーターの範囲を一時バッファーにコピーし、代わりにそのポインターを返します。 std ::両端キューのイテレータはrandom_access_iterator_tagを持っているので、イテレータのクラスをポインタに変換することを特化する

#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()); 
} 

これが最後のテストを失敗します。これを行うには、私は次のプログラムを書いています。

一般的に正しく動作するようにこのクラスを作成するにはどうすればよいですか?

は、私はVC++ 2010

Editを使用しています言及する必要がありますと仮定します。アダムが言うように、これは直接ことはできません(私はこれを恐れていました)。さて、私はこれを可能にする私自身の特性を定義しようとしています。私の試みは、以下を参照してください。彼らはSTD ::にiterator_traitsを使用したものと非常に類似しているため

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クラスを省略しました。

最初の2つの特殊化は機能しますが、2つのコメント付き特性文字列は機能しません。私の特定のSTL実装に依存することなく、動作するようにこれらをどのように記述しますか?

+0

'&* test2.begin()'は醜いです! – iammilind

+0

その醜いですが、それは動作します... – dsharlet

+1

これは本当に私が恐れていることはありません。唯一の可能性は、 'ベクトル :: iterator'のような特定のイテレータに特化することです。 'ベクトル :: reverse_iterator'は安全ではありません。 –

答えて

1

ポインタを明示的に特化してから、どのようなコンテナ(それがわかっているか)で扱うことができます(std::vectorの場合)。これはイテレータをポインタとして使うことができると言うコンテナの一般的な "特性"がないので、それほど悪くはありません。これは、コンテナプロバイダが明示的に行う必要がある保証です。 IteratorBufferの一般的なバージョンがサイレント少なくとも前方反復子カテゴリを想定し、入力専用イテレータで失敗することも


注(それは二度の範囲を使用するように)。

+0

あなたの答えをありがとう。私の編集を見て、私があなたのことを実装しようとしていますが、私は特定のイテレータクラスの専門化をどのように定義するかについて困惑しています。 – dsharlet

+0

私は試して失敗しました。合理的で標準的な解決策はないと考えています。しかし、もう少し試してみると、何かを見つけたらここに投稿します。 –

関連する問題