Reputation: 132350
Suppose I have a templated function which has a parameter used as an iterator (albeit without any concepts/requirements - C++17 or earlier), named my_iter
.
Can I generically ensure that iterator is a const iterator, or get a const iterator to the same position?
Note: Unlike in this question, which concerns an iterator
vs a const_iterator
of some assumed-known container class, here we don't know what that container class is, if it exists at all. Thus I don't want to write something like:
auto it = std::cbegin(my_container);
auto desired_iter = it + distance(it, my_iter);
as suggested in this method, nor even:
auto desired_iter = ContainerType::const_iterator(my_iter);
Upvotes: 0
Views: 262
Reputation: 30005
You could create a wrapper ConstIterator
class to ensure const-correctness:
#include <list>
#include <iostream>
#include <string>
template <typename Iterator>
class ConstIterator {
public:
ConstIterator(Iterator const it) /* Not explicit */
: it_{ it }
{}
auto& operator++() noexcept
{
++it_;
return *this;
}
[[nodiscard]] auto operator++(int) noexcept
{
auto copy = *this;
++it_;
return copy;
}
auto& operator--() noexcept
{
--it_;
return *this;
}
[[nodiscard]] auto operator--(int) noexcept
{
auto copy = *this;
--it_;
return copy;
}
[[nodiscard]] auto const& operator*() const noexcept
{
return *it_;
}
auto const* operator->() const noexcept
{
return &*it_; // const pointer
}
auto& operator+= (std::size_t const step) noexcept
{
it_ += step;
return *this;
}
auto& operator-= (std::size_t const step) noexcept
{
it_ -= step;
return *this;
}
auto operator+ (std::size_t const step) noexcept
{
auto copy = *this;
return copy += step;
}
auto operator- (std::size_t const step) noexcept
{
auto copy = *this;
return copy -= step;
}
auto operator- (ConstIterator const rhs) noexcept
{
return it_ - rhs.it_;
}
auto operator == (ConstIterator const rhs) noexcept
{
return it_ == rhs.it_;
}
auto operator != (ConstIterator const rhs) noexcept
{
return !(*this == rhs);
}
private:
Iterator it_;
};
// test it
template<typename Iter>
void print(Iter beg, Iter end) noexcept
{
ConstIterator<Iter> cbeg{ beg }; // const iterator
for (auto it = cbeg; it != end; ++it) {
std::cout << *it << ' '; // accessing works fine
}
std::cout << '\n';
// cbeg->clear(); // won't compile
// *cbeg = decltype(*cbeg){}; // won't compile
}
int main()
{
std::list<std::string> list{"1", "2", "3"};
print(list.begin(), list.end());
}
Upvotes: 1