2016-07-24 5 views
5

मैं निम्नलिखित वर्ग है स्थिरांक संदर्भ मान प्रकार के साथ एक ही नक्शे पर एक इटरेटर सूचक मान प्रकार के साथ एक unordered_map पर रूपांतरण इस वर्ग के _children के तत्वों को फिर से संशोधित करने में सक्षम होने के तत्वों को पुन: सक्रिय करने के लिए। यही कारण है कि मैं एक इटरेटर बनाना चाहता हूं जो pair<char, ptr_type> के बजाय pair<char, const Node&> के तत्वों को इंगित करता है।पुनरावर्तक

बेस इटरेटर कक्षा बनाना हाथ के काम के लिए थोड़ा जटिल लगता है। मैंने बूस्ट इटरेटर पर एक नज़र डाली है, मुझे लगता है कि transform_iterator जाने का रास्ता हो सकता है, लेकिन मुझे अभी तक यह नहीं मिला है कि इसे कैसे काम करना है।

जबकि मैं इसमें हूं, क्या किसी को पता है कि मैं boost-iterators में परिभाषित इटरेटर्स के विभिन्न उदाहरणों के उदाहरण कहां पा सकता हूं? प्रत्येक प्रकार के लिए डॉक्टर में केवल एक उदाहरण है, और वे हमेशा मेरी ज़रूरतों को पूरा नहीं करते हैं (मैं इस पुस्तकालय में नया हूं, मैंने कुछ स्पष्ट याद किया होगा)।

अद्यतन: यहाँ 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; 
}; 

का उपयोग कर यह दुर्भाग्य संकलन नहीं है पर मेरे प्रयास है, और निम्न त्रुटि देता है:

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

[ 'बढ़ावा देने :: transform_iterator'] (http://www.boost.org/doc/libs/1_53_0/libs/iterator/doc/transform_iterator.html) ऐसा करने में सक्षम होना चाहिए। या आप इन लाइनों के साथ अपना खुद का कस्टम इटरेटर रैपर लिख सकते हैं। –

उत्तर

1

मुझे लगता है कि इस कारण से boost::indirect_iterator मौजूद हो सकता है । एक (तुच्छ) पर बढ़ावा प्रलेखन से 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 को संतुष्ट करता है। आप इसे बिडरेक्शनल इटरेटर को तीन बार बढ़ा सकते हैं (हालांकि थोड़ा थकाऊ हो सकता है)।

इसे पोस्ट करने से पहले, मुझे डर है कि मैं आपकी पुनर्मूल्यांकन (बूस्ट-इटरेटर के उपयोग से अलग) को पूरा नहीं कर सका; 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::_pstd::pair जिसका संदर्भ में लिया जाता है है। यह अद्यतनों पर कॉपी-असाइन किया गया है, जो std::pair<char, const Node&> (संदर्भ वाला जोड़ी) प्रतिबंधित है।

std::pair<char, const Node&> के विकल्प std::pair<char, const Node*> या std::pair<char, std::reference_wrapper<const Node>> हैं। it->second.get().name() द्वारा it->second->name() बदलें आप std::reference_wrapper विकल्प का उपयोग करना चाहते हैं।

+0

इस पूर्ण उत्तर के लिए धन्यवाद और 'std :: pair ' का उपयोग करने के साथ समस्या को इंगित करने के लिए धन्यवाद। मैं आपको पूर्ण बक्षीस से सम्मानित करता हूं लेकिन मुझे इंटरनेट तक कोई पहुंच नहीं थी। – AntoineWDG

संबंधित मुद्दे