2016-07-24 6 views
5

const参照値型と同じマップ上のイテレータにポインタ値型とunordered_mapにイテレータを変換_childrenの要素を反復処理することはできません。そのため、pair<char, ptr_type>の代わりにpair<char, const Node&>という型の要素を指すイテレータを作成する必要があります。私は以下のクラスを持っている

基本イテレータクラスを作成することは、手近な作業のために少し複雑すぎるようです。私はブーストイテレータを見て、私はtransform_iteratorが行く方法かもしれないと思うが、私はまだそれを動作させる方法を発見していない。

私はここにいますが、boost-iteratorsで定義されているさまざまなイテレータの例をどこから見つけることができますか?各タイプのドキュメントには1つの例しかなく、私のニーズに合っているとは限りません(私はこのライブラリを初めて使用しています。

UPDATE

error: no type named ‘type’ in ‘boost::mpl::eval_if<boost::is_same<boost::iterators::use_default, boost::iterators::use_default>, boost::result_of<const Node::Transformer(const std::pair<const char, std::unique_ptr<Node> >&)>, boost::mpl::identity<boost::iterators::use_default> >::f_ {aka struct boost::result_of<const Node::Transformer(const std::pair<const char, std::unique_ptr<Node> >&)>}’ 
    typedef typename f_::type type; 
+0

['boost :: transform_iterator'](http://www.boost.org/doc/libs/1_53_0/libs/iterator/doc/transform_iterator.html)がそうすることができるはずです。または、これらの行に沿って独自のカスタムイテレータラッパーを記述することもできます。 –

答えて

1

私は、これはboost::indirect_iteratorが存在している理由かもしれないと思う:ここboost::transform_iterator

class Node { 
public: 
    typedef std::unique_ptr<Node> ptr_type; 
    typedef std::unordered_map<char, ptr_type> map_type; 


    struct Transformer { 
     std::pair<char, const Node&> operator()(const std::pair<char, ptr_type> &p) const { 
      return std::pair<char, const Node&>(p.first, *p.second); 
     } 
    }; 

    typedef boost::transform_iterator<Transformer, map_type::const_iterator, std::pair<char, const Node&>&, std::pair<char, const Node&>> const_iterator; 

    const_iterator begin() const { 
     return boost::make_transform_iterator<Transformer, map_type::const_iterator>(_children.begin(), Transformer()); 
    } 
    const_iterator end() const { 
     return boost::make_transform_iterator<Transformer, map_type::const_iterator>(_children.end(), Transformer()); 
    } 

private: 
    map_type _children; 
}; 

を使用しての私の試みは、それは残念ながらコンパイルし、次のエラーを与えていないです。 (ささい)map<char, char *>にブーストドキュメントからの例を適応:ブースト・イテレータの使用は必須ではない場合

#include <iostream> 
#include <map> 
#include <boost/iterator/indirect_iterator.hpp> 


int main() { 
    char characters[] = "abcdefg"; 
    size_t ncharacters = sizeof characters - 1; 
    char *charptr[ncharacters]; 

    for (size_t i = 0; i < ncharacters; ++i) { 
     charptr[i] = &characters[i]; 
    } 

    std::map <char, char *> map1; 
    for (size_t i = 0; i < ncharacters; ++i) { 
     map1[characters[i]] = charptr[i]; /* Trivial, just to demonstrate */ 
    } 

    boost::indirect_iterator<char * const*, char const> const_indirect_first(charptr), 
                 const_indirect_last(charptr + ncharacters); 

    std::copy(const_indirect_first, const_indirect_last, std::ostream_iterator<char>(std::cout, " ")); 
    std::cout << std::endl; 

    return 0; 
} 
+1

私は 'indirect_iterator'を使う考えが好きですが、これはマップにどのように適合していますか?マップを初期化するだけで、 'char *'配列に 'indirect_iterator'を使用しています。 – AntoineWDG

4

することは、あなた自身のイテレータを書くことができます。私はForwardIteratorを満たす1を掲示しています。 BidirectionalIteratorにそれを拡張することもできます(しかし、ビットが面倒かもしれません)。

投稿する前に、私はあなたの要求を満たすことができませんでした(ブーストイテレータの使用を除いて)。後者はコピーを禁止するためstd::pair<char, const Node&>の代わりにstd::pair<char, const Node*>が使用されます。これは、あなたがboost::transform_iteratorの例をコンパイルするのを妨げているかもしれません(私は確かではありません;私はブーストイテレータに慣れていません)。

とにかく、ここにはcode.cpp(125行の長さ)があります。テストのためのmain機能が含ま:

#include <unordered_map> 
#include <memory> 

class Node; 

template <class Map> 
class MyIterator { 
public: 
    // iterator member typedefs 
    using iterator_category = std::forward_iterator_tag; 
    using value_type = std::pair<char, const Node*>; 
    using difference_type = std::ptrdiff_t; 
    using pointer = value_type*; 
    using reference = value_type&; 

    // typedef for underlying iterator 
    using underlying_iterator = typename Map::const_iterator; 

    // constructors 
    // takes an underlying iterator 
    explicit MyIterator(underlying_iterator it) : _it(std::move(it)) {} 
    // default constructor; required by ForwardIterator 
    MyIterator() = default; 

    // dereference; required by InputIterator 
    reference operator*() { 
     update(); 
     return _p; 
    } 

    // dereference; required by InputIterator 
    pointer operator->() { 
     update(); 
     return &_p; 
    } 

    // increment; required by Iterator 
    MyIterator<Map>& operator++() { 
     ++_it; 
     return *this; 
    } 

    // increment; required by InputIterator 
    MyIterator<Map> operator++(int) { 
     auto mit = *this; 
     ++*this; 
     return mit; 
    } 

    // comparison; required by EqualityComparable 
    bool operator==(const MyIterator<Map>& mit) const { 
     return _it == mit._it; 
    } 

    // comparison; required by InputIterator 
    bool operator!=(const MyIterator<Map>& mit) const { 
     return !(*this == mit); 
    } 

private: 
    // this method must be called at dereference-time but not 
    // traverse-time in order to prevent UB at a wrong time. 
    void update() { 
     _p = value_type{_it->first, &*(_it->second)}; 
    } 

    // the underlying iterator that tracks the map 
    underlying_iterator _it; 
    // the pair of the desired type. without it, e.g. operator-> doesn't 
    // work; it has to return a pointer, and the pointed must not be a 
    // temporary object. 
    value_type _p; 
}; 

class Node { 
public: 
    typedef std::unique_ptr<Node> ptr_type; 
    typedef std::unordered_map<char, ptr_type> map_type; 

    typedef MyIterator<map_type> const_iterator; 

    const_iterator begin() const { 
     return const_iterator{_children.begin()}; 
    } 
    const_iterator end() const { 
     return const_iterator{_children.end()}; 
    } 

private: 
    map_type _children; 

// additional members for testing purposes. 
public: 
    Node(std::string name) : _name(std::move(name)) {} 
    Node(std::string name, map_type&& children) : 
     _children(std::move(children)), _name(std::move(name)) {} 
    std::string const& name() const { 
     return _name; 
    } 
private: 
    std::string _name; 
}; 

#include <iostream> 

// test program; construct a simple tree and print children. 
int main() { 
    typedef std::unique_ptr<Node> ptr_type; 
    typedef std::unordered_map<char, ptr_type> map_type; 

    ptr_type leaf1(new Node("leaf1")); 
    ptr_type leaf2(new Node("leaf2")); 
    ptr_type leaf3(new Node("leaf3")); 
    map_type branch; 
    branch.emplace('1', std::move(leaf1)); 
    branch.emplace('2', std::move(leaf2)); 
    branch.emplace('3', std::move(leaf3)); 
    Node parent("parent", std::move(branch)); 

    for (auto it = parent.begin(); it != parent.end(); ++it) { 
     std::cout << it->first << ' ' << it->second->name() << '\n'; 
    } 

    return 0; 
}; 

コンパイルコマンドを:

g++ -std=c++11 -g -O2 -Wall code.cpp 

私の出力:

3 leaf3 
2 leaf2 
1 leaf1 

MyIteratorあなたがstd::unordered_mapを変更したいときなどするように、テンプレートクラスとして書かれていますstd::map、あなたはMyIteratorを変更する必要はありません。)

何物事を複雑にすることはoperator*std::pairへの参照を返さなければならないということです。つまり、std::pairというオブジェクト(非暫定)がどこかに存在しなければならないことを意味します。operator->( "参照"を "ポインタ"で置き換えます)と同じです。

ここで、MyIterator::_pは、参考文献となるstd::pairです。これは更新時にコピー割り当てされ、std::pair<char, const Node&>(参照を含むペア)は禁止されています。

std::pair<char, const Node&>の代替品は、std::pair<char, const Node*>またはstd::pair<char, std::reference_wrapper<const Node>>です。代替std::reference_wrapperを使用する場合は、をit->second.get().name()に交換してください。

+0

この完全な答えと、 'std :: pair 'を使って問題を指摘してくれてありがとう。私はあなたに完全な恩恵を与えていただろうが、私はインターネットにアクセスできなかった。 – AntoineWDG

関連する問題