3

I've found an example at cpluplus.com. Here it is:

#include <iostream>
#include <string>
#include <regex>

int main ()
{
  std::string s ("This subject has a submarine as a subsequence");
  std::smatch m;
  std::regex e ("\\b(sub)([^ ]*)");   // Matches words beginning by "sub"

  std::cout << "Target sequence: " << s << std::endl;
  std::cout << "Regular expression: /\\b(sub)([^ ]*)/" << std::endl;
  std::cout << "The following matches and submatches were found:" << std::endl;

  while (std::regex_search (s,m,e)) {
    for (auto x:m) 
      std::cout << x << " ";
    std::cout << std::endl;
    s = m.suffix().str();
  }

  return 0;
}

Why can we use a for-each loop on the object of the type smatch?

I'm used to using the foreach loop only with STL-containers...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 1
    This is actually called a [ranged based for loop](http://en.cppreference.com/w/cpp/language/range-for). [foreach](http://en.cppreference.com/w/cpp/algorithm/for_each) is something else – NathanOliver Jun 17 '15 at 17:51

1 Answers1

4

The so-called foreach loop looks for the begin() and end() in the scope they are needed. So, if your class implements begin() and end() with iterator interface you may use new foreach loop.

As @NathanOliver said, you should avoid calling this loop as foreach loop because you may confuse it with std::for_each algorithm. Call it range-based for.

UPDATE:

You may return any thing from begin() and end() methods. Let me tell you how it works from the beginning:

  1. std::begin() and std::end() both look for Type::begin() and Type::end() respectively.
  2. They get this object and work with it just like with a pointer. Why pointer? Because all stl- and stl-compatible iterators are using pointer interface.
  3. From the 2 point, you may return any thing from your begin() and end() that looks like a pointer (uses its interface): a pointer, or an iterator. Pointer actually is just like a random-access iterator.

Also, STL provides a small concept about iterators:

everything that looks like an iterator is an iterator.

Example about pointer interface:

struct A
{ 
    int* val = new int[5];

    int* begin() const {
        return val;
    }

    int* end() const {
        return val + 5;
    }
};


int main ()
{
    A a;
    for (const auto &v : a) {
        std::cout << "value: " << v << std::endl;
    }

    return 0;
}

Reading section:

Nicolai M. Josuttis C++11 STDLIB

STL compatible iterators for custom containers

Writing STL compatible iterators

How to implement an STL-style iterator and avoid common pitfalls

Community
  • 1
  • 1
VP.
  • 15,509
  • 17
  • 91
  • 161
  • You mean the objects returned by the functions should behave jsut like iterators. I mean, support all overloaded operators iterators do. Is that right? –  Jun 17 '15 at 19:30
  • An iterator is not a pointer is not an iterator (it might be though), and the Standard describes in quite exact terms what a range-based for loop is semantically. If the provided `begin` and `end` functions return objects that work in that construct (i.e. they pretty much behave as ForwardIterators) then you can use range-based for on your type. – rubenvb Jun 18 '15 at 09:22
  • @rubenvb Did I say somewhere that iterator is a pointer? I said exactly what you wrote here. – VP. Jun 18 '15 at 09:24
  • 1
    `begin` and `end` should return objects with an *(forward) iterator* interface, not a "pointer interface". A pointer (to somewhere inside a contiguous block of memory) is indeed a random access iterator, but any one pointer isn't just magically an iterator. C++ algorithms and constructs like range-based for are defined in terms of iterators, not pointers. – rubenvb Jun 18 '15 at 09:27
  • 1
    @rubenvb Wait, but both pointers and iterators have the same semantic. So why couldn't we say that iterators are pointers in some degree? –  Jun 18 '15 at 09:36
  • @rubenvb Josuttis, quote: "The STL designers decided to use the pointer interface for the iterators to let pointers replace iterators. If something behaves like an iterator so it is an iterator. In fact, pointers are random-access iterators." I have this book right in front of me. So, for `int arr[]` we may use `std::begin()` which returns a pointer to zero element and `std::end()` which returns a pointer to `[0] + NumOfElementsIn(arr)`. I dont understand your point because you repeat exactly what I wrote. – VP. Jun 18 '15 at 09:37
  • You quote "If something behaves like an iterator so it is an iterator." Your answer implies the inverse. Also, STL is so nineties. It's the Standard Library now. There was and is and never will be a freestanding `std::begin` nor `std::end` in the STL. – rubenvb Jun 18 '15 at 09:42
  • @Victor: Point 2 "They get this object and work with it just like with a pointer. Why pointer? Because all stl- and stl-compatible iterators are using pointer interface." and Point 3: "From the 2 point, you may return any thing from your begin() and end() that looks like a pointer (uses its interface)". – rubenvb Jun 18 '15 at 09:45
  • @rubenvb You got me about `standard library` and `stl` terms but a lot of people confuse this sometimes. What wrong did I say in your quote? Don't you see logic? Iterators use pointer interface. So you need to return something with pointer interface, and it will look like an iterator. Is this wrong? – VP. Jun 18 '15 at 09:52