I have a container similar to next one:
class MySpecialContainer
{
std::vector<std::tuple<InternalType, Type1, Type2>> _vec;
};
where Type1
and Type2
are usable outside the container and InternalType
is used only inside the container. To iterate through the elements from outside I'm using a member function similar to next one:
void MySpecialContainer::iterate(std::function<void(const Type1&, const Type2&)> fun)
{
for(auto& it : _vec)
{
fun(std::get<1>(it), std::get<2>(it));
}
}
As you can see this approach has several limitations, like not being able to iterate on a subrange or not being able to use non mutating std::algorithms
.
Considering MySpecialContainer
elements are non mutable from outside from logical considerations does it make sense to provide only const_iterator
for it?
If the answer if yes for the first question, is it better to...?
separate _vec
into 2 containers, one for InternalType
and one for std::pair<Type1, Type2>
, keep them synchronized and just return const_iterator
for second vector
keep the vector as it is now and make a custom iterator that exposes only const Type1
and const Type2
Just exposing const iterators is fine. There is even precedence in the standard for this, as std::set
effectively does this. Technically, iterator
and const_iterator
can be different types, but you are not allowed to modify the elements through either type of iterator, as that could break the invariants for set
.
One option is to expose iterators that give access to certain fields only of your elements, e.g.:
#include <vector>
#include <tuple>
#include <boost/iterator/transform_iterator.hpp>
struct Type1 {};
struct Type2 {};
struct InternalType {};
class MySpecialContainer
{
typedef std::vector<std::tuple<InternalType, Type1, Type2>> Vec;
Vec _vec;
struct Extractor
{
std::tuple<Type1&, Type2&> operator()(Vec::value_type& t) const {
return std::tie(std::get<1>(t), std::get<2>(t));
}
std::tuple<Type1 const&, Type2 const&> operator()(Vec::value_type const& t) const {
return std::tie(std::get<1>(t), std::get<2>(t));
}
};
public:
typedef boost::transform_iterator<Extractor, Vec::iterator> iterator;
typedef boost::transform_iterator<Extractor, Vec::const_iterator> const_iterator;
iterator begin() { return iterator{_vec.begin()}; }
iterator end() { return iterator{_vec.end()}; }
const_iterator begin() const { return const_iterator{_vec.begin()}; }
const_iterator end() const { return const_iterator{_vec.end()}; }
};
int main() {
MySpecialContainer c;
for(auto x : c) {
}
}
Note that through non-const iterators you can still update the exposed values because the trasform iterator returns a tuple of references.
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