patterncppMinor
Iterator adaptor for iterators returning tuple-like values
Viewed 0 times
adaptoriteratorliketuplereturningforvaluesiterators
Problem
Today, I will require your help to improve an iterator adapter. The goal of the adapter (I called it
Here is the header file:
And here is the implementation file:
```
template
get_iterator::get_iterator()
= default;
template
get_iterator::get_iterator(Iterator it):
_current(it)
{}
template
template
get_iterator::get_iterator(const get_iterator& other):
_current(other.base())
{}
template
template
auto get_iterator::operator=(const get_iterator& other)
-> get_iterator&
{
if (&other != this)
{
_current = other.base();
}
retur
get_iterator) is to adapt std::map iterators for example: map iterators return std::pair instances, a get_iterator::iterator> will provide an iterator which iterates through the keys while a get_iterator::iterator> will provide an iterator which iterates through the values. Here is my implementation:Here is the header file:
template
class get_iterator:
public std::iterator::iterator_category,
typename std::remove_reference(*Iterator{}))>::type,
typename std::iterator_traits::difference_type>
{
private:
Iterator _current;
public:
using iterator_type = Iterator;
using value_type = typename std::remove_reference(*_current))>::type;
using pointer = value_type*;
using reference = value_type&;
get_iterator();
explicit get_iterator(Iterator it);
template
get_iterator(const get_iterator& other);
template
auto operator=(const get_iterator& other)
-> get_iterator&;
auto base() const
-> Iterator;
auto operator*() const
-> reference;
auto operator->() const
-> pointer;
auto operator++()
-> get_iterator&;
auto operator++(int)
-> get_iterator&;
auto operator--()
-> get_iterator&;
auto operator--(int)
-> get_iterator&;
};And here is the implementation file:
```
template
get_iterator::get_iterator()
= default;
template
get_iterator::get_iterator(Iterator it):
_current(it)
{}
template
template
get_iterator::get_iterator(const get_iterator& other):
_current(other.base())
{}
template
template
auto get_iterator::operator=(const get_iterator& other)
-> get_iterator&
{
if (&other != this)
{
_current = other.base();
}
retur
Solution
Define
As pointed by @Yuushi, Boost has a
The function object would have had another advantage had Boost allowed its
I would have loved to use ADL to find the most suitable
Add a construction function
Let's assume that we still want to write a
Moreover, adding such a construction function is consistent with the standard library. After all,
Miscellaneous tidbits
There are more things that could be improved, but they are more subtle and less interesting:
-
The check
-
-
More iterator-related functions could have been overloaded to support the requirements of a [
-
It would be better to put
get_iterator in terms of transform_iteratorAs pointed by @Yuushi, Boost has a
transform_iterator class which will apply a function to the return value of operator*. Therefore, get_iterator could be define as an alias template:struct getter
{
template
auto operator()(T&& value)
-> decltype(auto)
{
return std::get(std::forward(arg));
}
};
template
using = boost::iterators::transform_iterator, Iterator>;The function object would have had another advantage had Boost allowed its
transform_iterator to take advantage of the empty base optimization. Unfortunately, this is not the case right now, but using a function object may trigger a free improvement when Boost finally implements EBO in transform_iterator.I would have loved to use ADL to find the most suitable
get to use, but get always need an integer template parameter. And ADL is not triggered when a template parameter is provided by hand instead of being deduced.Add a construction function
Let's assume that we still want to write a
get_iterator by hand. While the integer template parameter is always provided by hand, the ability to deduce the Iterator template parameter is still something we want to have. Therefore, we will add a construction function:template
auto make_get_iterator(Iterator it)
-> get_iterator
{
return get_iterator(it);
}Moreover, adding such a construction function is consistent with the standard library. After all,
std::make_reverse_iterator was added to C++14 for consistency.Miscellaneous tidbits
There are more things that could be improved, but they are more subtle and less interesting:
-
The check
&other != this in operator= seems pretty useless. It is almost always a pessimization and I cannot think of a scenario where assigning base() to itself would go wrong.-
operator++(int) and operator--(int) shoud return get_iterator instead of get_iterator&. Currently they return references to temporary variables, which is plain wrong. That proves that I didn't write proper tests.-
More iterator-related functions could have been overloaded to support the requirements of a [
RandomAccessIterator][5] when needed since nothing prevents it and supporting more iterators is better than support fewer. The functions that could have been added are operator+, operator-, operator+=, opperator-= and opeator[].-
It would be better to put
= default on its first declaration instead of separating the declaration and the definition of the default constructor. The rationale is that Iterator it{} can zero-initialize the iterator instead of dedault-initializing it if = default appears on the first declaration. I have no idea whether this can change something for any iterator, but initializing memory with zero cannot be worse than initializing it with garbage.Code Snippets
struct getter
{
template<typename T>
auto operator()(T&& value)
-> decltype(auto)
{
return std::get<N>(std::forward<T>(arg));
}
};
template<std::size_t N, typename Iterator>
using = boost::iterators::transform_iterator<getter<N>, Iterator>;template<std::size_t N, typename Iterator>
auto make_get_iterator(Iterator it)
-> get_iterator<N, Iterator>
{
return get_iterator<N, Iterator>(it);
}Context
StackExchange Code Review Q#38421, answer score: 5
Revisions (0)
No revisions yet.