I have the following class :
#include <unordered_map>
#include <memory>
class Node {
public:
    typedef std::unique_ptr<Node> ptr_type;
    typedef std::unordered_map<char, ptr_type> map_type;
    typedef /**???**/ const_iterator;
    const_iterator begin() const;
    const_iterator end() const;
private:
    map_type _children;
};
As you can see, I want a way fo a user of this class to iterate over elements of _children without being able to modify them. That is why I want to create an iterator that point to elements of type pair<char, const Node&> instead of pair<char, ptr_type>. 
Creating a base iterator class seems a little too complicated for the task at hand. I have taken a look at boost iterator, I think transform_iterator may be the way to go, but I have not yet found how to make it work. 
While I'm at it, does anyone know where I can find examples of the different examples of iterators defined in boost-iterators ? There is only one example in the doc for each type, and they do not always fit my needs (I'm new to this library, I may have missed something obvious).
UPDATE: Here is my attempt at using 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;
};
It unfortunately does not compile, and gives the following error:
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;
                If use of boost-iterator is not mandatory, you can write your own iterator. I'm posting one, which satisfies ForwardIterator. You can expand it to BidirectionalIterator trivially (it may be a bit tedious, however).
Before posting it, I'm afraid I couldn't fulfill your reqirement (aside from use of boost-iterator); std::pair<char, const Node*> is used instead of std::pair<char, const Node&> because the latter prohibits copying. Maybe this is what prevented you from compiling your boost::transform_iterator example (I'm not certain; I'm not so familiar with boost-iterator).
Anyway, here is the code.cpp (125 lines long). main function for testing included:
#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;
};
compilation command:
g++ -std=c++11 -g -O2 -Wall code.cpp
my output:
3 leaf3
2 leaf2
1 leaf1
MyIterator is written as a template class so that when you want to change std::unordered_map to e.g. std::map, you don't need to modify MyIterator ;)
What complicates things is that the operator* must return a reference to an std::pair; it means that there must exist a (non-temporary) object of std::pair somewhere, otherwise that reference becomes a dangling reference. Same for the operator-> (replace "reference" by "pointer").
Here, MyIterator::_p is the std::pair whose reference is taken. This is copy-assigned upon updates, which std::pair<char, const Node&> (pair containing a reference) prohibits.
Alternatives to std::pair<char, const Node&> are std::pair<char, const Node*> or std::pair<char, std::reference_wrapper<const Node>>. Replace it->second->name() by it->second.get().name() if you choose to use std::reference_wrapper alternative.
I think this might be the reason boost::indirect_iterator exists. Adapting an example from the boost documentation on a (trivial) 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;
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With