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{});
CodePudding user response:
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 in general. There is another consideration whether your range implementation works in an expected way.
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{})