Lets say I have an input iterator type MyInputIter (which I use to traverse a tree-like structure) that satisfies the std::input_iterator concept.
Are there any reasons why I shouldn’t define begin() and end() on the iterator itself?
struct MyInputIter
{
// iterator stuff omitted
auto begin() const { return *this; }
auto end() const { return MySentinel{}; }
};
Reason being that I don’t have to create another type just to wrap begin and end so I can use it in a for loop:
MyInputIter iterate(TreeNode root, FilterPattern pattern)
{
return MyInputIter{ root, pattern };
}
void foo()
{
for (auto item : iterate(someRandomTreeNode, "*/*.bla"))
process(item);
}
while also being able to use it as an iterator:
std::vector<TreeNode> vec(iterate(someRandomTreeNode, "*"), MySentinel{});
>Solution :
Are there any reasons why I shouldn’t define begin() and end() on the iterator itself?
Potential issues to consider:
- Implementing those functions for the iterator may be expensive. Either because of need to traverse the structure to find them, or because of extra state stored in the iterator.
- It may be confusing since it deviates from common patterns. Edit: As pointed out by 康桓瑋, there’s precedent for iterators that are ranges in
std::filesystem::directory_iterator, so this may not a significant issue.
Reason being that I don’t have to create another type
As far as I can tell, you don’t need to create another type. You can use:
std::ranges::subrange(MyInputIter{ root, pattern }, MySentinel{})