Home > database >  Can I define begin and end on an input iterator?
Can I define begin and end on an input iterator?

Time:04-01

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:

  1. 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.
  2. 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{})
  • Related