My original question
How can I write a C++ class that works with C++20 std::ranges library?
Origin of my problem
I tried to write a facade class with iterators in C++. But my compiler (clang++18) told me that requirements are not met and the deepest unmet requirement is: /usr/bin/../lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/ranges:946:30: note: because '__adaptor::__is_range_adaptor_closure_fn(__t, __t)' would be invalid: no matching function for call to '__is_range_adaptor_closure_fn'.
My journey towards solving this problem so far
I read through several SO post including:
- How to make my custom type to work with "range-based for loops"?
- Creating an Iterator with C++20 Concepts for custom container
- What is the difference between std::ranges::begin and std::begin?
- What am I missing in my custom std::ranges iterator?
before I finally ended up here: How to support range adaptors in custom container?
My new questions
While reading the accepted answer of bolov on that last post, several new questions arose at my side:
- Why does the
Iteratorneed to be default constructable? In my current implementation this is an issue because it contains const references to large objects. (That might be resolvable, but if one should and how are different questions.) Related: Why do iterators need to be default-constructible - Why does one need the
difference_typeif the aim is astd::forward_iteratorwithout an implementation ofoperator--andoperator-? Related: How to handle iterator::difference_type when you have no way of measuring the difference?
Example
The following is a simplifyed example of my facade class.
#include <cstddef>
#include <iterator>
#include <unordered_set>
using Set = std::unordered_set<std::ptrdiff_t>;
class MyFacadeClass {
private:
class Iterator {
public:
using iterator_category = std::forward_iterator_tag;
using value_type = std::ptrdiff_t;
Iterator(const std::ptrdiff_t self,
const Set& a,
const Set& b,
const Set::const_iterator it,
const bool inB = false) :
pSelf(self),
pA(a),
pB(b),
pIt(it),
pInB(inB) {}
std::ptrdiff_t operator*() const { return *pIt; }
bool operator!=(const Iterator& other) const { return pIt != other.pIt; }
Iterator& operator++() {
if (pInB) {
++pIt;
return *this;
}
else {
do {
++pIt;
if (pIt == pA.end()) {
pIt = pB.begin();
pInB = true;
return *this;
}
} while (*pIt == pSelf);
return *this;
}
}
private:
const std::ptrdiff_t pSelf;
const Set& pA;
const Set& pB;
Set::const_iterator pIt;
bool pInB;
};
static_assert(std::forward_iterator<Iterator>);
public:
Iterator begin() const { return Iterator(self, pA, pB, pA.begin()); }
Iterator end() const { return Iterator(self, pA, pB, pB.end()); }
private:
const std::ptrdiff_t self;
const Set& pA;
const Set& pB;
};
Goal
It would be nice to use c++ syntax like
for(const std::ptrdiff_t& member : myClass | std::views::filter(CONDITION)) {
}
Here we pretend myClass is of Type const MyFacadeClass defined earlier in the code.
Clarification of the listed questions would be nice. Thanks in advance!