c++boostboost-range

How can I make my container compatible with boost::range?


I'm rolling a custom, standard-like container and I'd like to have it compatible with the boost::range library.

So far it works with all the STL algorithms and it also satisfies the following:

BOOST_CONCEPT_ASSERT((boost::InputIterator<my_container::const_iterator>));
BOOST_CONCEPT_ASSERT((boost::Container<my_container>));

But when I try to use it in this context:

auto r = c | boost::adaptors::indexed();

It seems to be missing some templated metadata. The errors are something like

error: no type named 'type' in boost::range::iterator<my_container, void>
>> typename range_iterator<SinglePassRange>::type

Is there a similar concept assert I can use to help me complete the missing implementation for my type? Or maybe even an article explaining how to make a container boost::range compatible? I'm assuming I do not need to actually include boost types in my implementation, since the STL obviously doesn't.

Any help greatly appreciated! :-)

Edit: minimal(ish) example

#include <catch2/catch.hpp>

#include <boost/concept_check.hpp>
#include <boost/concept/assert.hpp>
#include <boost/range/adaptor/indexed.hpp>

#include <algorithm>

SCENARIO("container")
{
    class my_container
    {
    public:
        class const_iterator
        {
        public:
            using value_type = const int;
            using pointer = const int*;
            using reference = const int&;
            using difference_type = std::ptrdiff_t;
            using iterator_category = std::input_iterator_tag;
            const_iterator() = default;
            bool operator==(const_iterator other) const noexcept { return d == other.d; }
            bool operator!=(const_iterator other) const noexcept { return !(*this == other); }
            reference operator*() const { return *d; }
            pointer operator->() const { return d; }
            const_iterator& operator++() { ++d; return *this; }
            const_iterator operator++(int) { return d++; }
        private:
            friend my_container;
            const_iterator(const int* p) : d(p) {}
            const int* d{nullptr};
        };
        using value_type = int;
        using const_reference = const int&;
        using const_pointer = const int*;
        using size_type = std::size_t;
        using difference_type = std::ptrdiff_t;
        my_container() : data({0, 1, 2, 3, 4}) {}
        const_iterator begin() const { return const_iterator(data.data()); }
        const_iterator end() const { return const_iterator(data.data() + 5); }
        size_type size() const { return 5; }
        size_type max_size() const { return 5; }
        bool empty() const { return false; }
    private:
        std::array<int, 5> data;
    };

    BOOST_CONCEPT_ASSERT((boost::InputIterator<my_container::const_iterator>));
    BOOST_CONCEPT_ASSERT((boost::Container<my_container>));

    GIVEN("a container") {
        my_container container;
        WHEN("use std::algorithms") {
            auto itr = std::find(container.begin(), container.end(), 3);
            THEN("element is found") {
                CHECK(itr != container.end());
            }
        }
        WHEN("use boost range") {
            // wont compile
            auto r = container | boost::adaptors::indexed();
        }
    }
}

Solution

  • You need iterator as well as const_iterator. Try:

        using iterator = const_iterator;