I have a container called Integers, which simply wraps an array as follows.
class Integers
{
private:
int m_data[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
};
Now I add two iterators, one regular and the other const iterator as follows.
struct Iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using pointer = int *; // or also value_type*
using reference = int &; // or also value_type&
Iterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
// Prefix increment
Iterator &operator++()
{
m_ptr++;
return *this;
}
// Postfix increment
Iterator operator++(int)
{
Iterator tmp = *this;
++(*this);
return tmp;
}
Iterator operator+(const int &right_operand)
{
// std::cout << "right oprand: " << right_operand << std::endl;
for (int i = 0; i < right_operand; i++)
{
m_ptr++;
}
return *this;
}
friend bool operator==(const Iterator &a, const Iterator &b) { return a.m_ptr == b.m_ptr; };
friend bool operator!=(const Iterator &a, const Iterator &b) { return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
The constant one is as follows.
struct ConstIterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using pointer = int *; // or also value_type*
using reference = int &; // or also value_type&
ConstIterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
// Prefix increment
ConstIterator &operator++()
{
m_ptr++;
return *this;
}
// Postfix increment
ConstIterator operator++(int)
{
ConstIterator tmp = *this;
++(*this);
return tmp;
}
ConstIterator operator+(const int &right_operand)
{
// std::cout << "right oprand: " << right_operand << std::endl;
for (int i = 0; i < right_operand; i++)
{
m_ptr++;
}
return *this;
}
friend bool operator==(const ConstIterator &a, const ConstIterator &b) { return a.m_ptr == b.m_ptr; };
friend bool operator!=(const ConstIterator &a, const ConstIterator &b) { return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
So the entire Integer class along with its two iterators is as follows.
#include <iostream>
#include <algorithm>
#include <vector>
#include <ranges>
class Integers
{
public:
struct Iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using pointer = int *; // or also value_type*
using reference = int &; // or also value_type&
Iterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
// Prefix increment
Iterator &operator++()
{
m_ptr++;
return *this;
}
// Postfix increment
Iterator operator++(int)
{
Iterator tmp = *this;
++(*this);
return tmp;
}
Iterator operator+(const int &right_operand)
{
// std::cout << "right oprand: " << right_operand << std::endl;
for (int i = 0; i < right_operand; i++)
{
m_ptr++;
}
return *this;
}
friend bool operator==(const Iterator &a, const Iterator &b) { return a.m_ptr == b.m_ptr; };
friend bool operator!=(const Iterator &a, const Iterator &b) { return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
struct ConstIterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using pointer = int *; // or also value_type*
using reference = int &; // or also value_type&
ConstIterator(pointer ptr) : m_ptr(ptr) {}
reference operator*() const { return *m_ptr; }
pointer operator->() { return m_ptr; }
// Prefix increment
ConstIterator &operator++()
{
m_ptr++;
return *this;
}
// Postfix increment
ConstIterator operator++(int)
{
ConstIterator tmp = *this;
++(*this);
return tmp;
}
ConstIterator operator+(const int &right_operand)
{
// std::cout << "right oprand: " << right_operand << std::endl;
for (int i = 0; i < right_operand; i++)
{
m_ptr++;
}
return *this;
}
friend bool operator==(const ConstIterator &a, const ConstIterator &b) { return a.m_ptr == b.m_ptr; };
friend bool operator!=(const ConstIterator &a, const ConstIterator &b) { return a.m_ptr != b.m_ptr; };
private:
pointer m_ptr;
};
// ...
Iterator begin() { return Iterator(&m_data[0]); }
Iterator end() { return Iterator(&m_data[20]); } // 20 is out of bounds
ConstIterator cbegin() { return ConstIterator(&m_data[0]); }
ConstIterator cend() { return ConstIterator(&m_data[20]); } // 20 is out of bounds
private:
int m_data[20] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
};
Note the begin()
, end()
and their constant counter parts cbegin()
, cend()
.
So far so good.
I am just trying to use the find algorithm on my Integer instance as follows.
int main()
{
Integers integers;
std::ranges::find(integers.begin(), integers.end(), 8);
// std::ranges::find(integers.cbegin(), integers.cend(), 8);
return 0;
}
This does not compile, it throws bunch of errors, which I cannot decipher. I tried with cbegin and cend as well.
This is spinning my head, please help.
I compiled with cpp 20 as well as 23 as follows.
g++ "-static" -o main.exe .*.cpp -std=c++20
g++ "-static" -o main.exe .*.cpp -std=c++23
Some of the errors are as follows.
.main.cpp: In function 'int main()':
.main.cpp:112:22: error: no match for call to '(const std::ranges::__find_fn) (Integers::Iterator, Integers::Iterator, int)'
112 | std::ranges::find(integers.begin(), integers.end(), 8);
| ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_util.h:473:7: note: candidate: 'template<class _Iter, class _Sent, class _Tp, class _Proj> requires (input_iterator<_Iter>) && (sentinel_for<_Sent, _Iter>) && (indirect_binary_predicate<std::ranges::equal_to, typename std::__detail::__projected<_I1, _P1>::__type, const _Tp*>) constexpr _Iter std::ranges::__find_fn::operator()(_Iter, _Sent, const _Tp&, _Proj) const'
473 | operator()(_Iter __first, _Sent __last,
| ^~~~~~~~
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_util.h:473:7: note: template argument deduction/substitution failed:
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_util.h:473:7: note: constraints not satisfied
C:/Program Files/mingw64/include/c++/13.2.0/concepts: In substitution of 'template<class _Iter, class _Sent, class _Tp, class _Proj> requires (input_iterator<_Iter>) && (sentinel_for<_Sent, _Iter>) && (indirect_binary_predicate<std::ranges::equal_to, typename std::__detail::__projected<_I1, _P1>::__type, const _Tp*>) constexpr _Iter std::ranges::__find_fn::operator()(_Iter, _Sent, const _Tp&, _Proj) const [with _Iter = Integers::Iterator; _Sent = Integers::Iterator; _Tp = int; _Proj = std::identity]':
.main.cpp:112:22: required from here
C:/Program Files/mingw64/include/c++/13.2.0/concepts:152:13: required for the satisfaction of 'constructible_from<_Tp>' [with _Tp = Integers::Iterator]
C:/Program Files/mingw64/include/c++/13.2.0/concepts:157:13: required for the satisfaction of 'default_initializable<_Tp>' [with _Tp = Integers::Iterator]
C:/Program Files/mingw64/include/c++/13.2.0/concepts:272:13: required for the satisfaction of 'semiregular<_Sent>' [with _Sent = Integers::Iterator]
C:/Program Files/mingw64/include/c++/13.2.0/bits/iterator_concepts.h:639:13: required for the satisfaction of 'sentinel_for<_Sent, _Iter>' [with _Sent = Integers::Iterator; _Iter = Integers::Iterator]
C:/Program Files/mingw64/include/c++/13.2.0/concepts:153:30: note: the expression 'is_constructible_v<_Tp, _Args ...> [with _Tp = Integers::Iterator; _Args = {}]' evaluated to 'false'
153 | = destructible<_Tp> && is_constructible_v<_Tp, _Args...>;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_util.h:487:7: note: candidate: 'template<class _Range, class _Tp, class _Proj> requires (input_range<_Range>) && (indirect_binary_predicate<std::ranges::equal_to, typename std::__detail::__projected<decltype(std::ranges::__cust_access::__begin((declval<_Container&>)())), _Proj>::__type, const _Tp*>) constexpr std::ranges::borrowed_iterator_t<_Range> std::ranges::__find_fn::operator()(_Range&&, const _Tp&, _Proj) const'
487 | operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const
| ^~~~~~~~
In file included from C:/Program Files/mingw64/include/c++/13.2.0/string_view:48,
from C:/Program Files/mingw64/include/c++/13.2.0/bits/basic_string.h:47,
from C:/Program Files/mingw64/include/c++/13.2.0/string:54:
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_base.h: In substitution of 'template<class _Range, class _Tp, class _Proj> requires (input_range<_Range>) && (indirect_binary_predicate<std::ranges::equal_to, typename std::__detail::__projected<decltype(std::ranges::__cust_access::__begin((declval<_Container&>)())), _Proj>::__type, const _Tp*>) constexpr std::ranges::borrowed_iterator_t<_Range> std::ranges::__find_fn::operator()(_Range&&, const _Tp&, _Proj) const [with _Range = Integers::Iterator; _Tp = Integers::Iterator; _Proj = int]':
.main.cpp:112:22: required from here
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_base.h:501:13: required for the satisfaction of 'range<_Tp>' [with _Tp = Integers::Iterator]
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_base.h:590:13: required for the satisfaction of 'input_range<_Range>' [with _Range = Integers::Iterator]
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_base.h:501:21: in requirements with '_Tp& __t' [with _Tp = Integers::Iterator]
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_base.h:503:22: note: the required expression 'std::ranges::__cust::begin(__t)' is invalid
503 | ranges::begin(__t);
| ~~~~~~~~~~~~~^~~~~
C:/Program Files/mingw64/include/c++/13.2.0/bits/ranges_base.h:504:20: note: the required expression 'std::ranges::__cust::end(__t)' is invalid
504 | ranges::end(__t);
| ~~~~~~~~~~~^~~~~
cc1plus.exe: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
8