einpoklum
einpoklum

Reputation: 132350

Making an arbitrary iterator const

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

Answers (1)

Aykhan Hagverdili
Aykhan Hagverdili

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

Related Questions