// Terminating iterations over ranges with iterator sentinals
// we will build an iterator together with a range class,
// which enables us to iterate over a string with unknown lengh, without
// finding the end position in advance
#include <iostream>
// The iterator sentinel is a very central element of this section.
// Its class definition can stay completely empty.
class cstring_iterator_sentinel {};
// Implement the iterator. It will contain a string pointer, which
// is the container we iterate ove
class cstring_iterator {
constchar *s {nullptr};
public:
// the constructor initializes the internal string pointer to whatever
// string the user provides. Let's make the constructor explicit in
// order to prevent accidental implicit conversion
explicit cstring_iterator(constchar *str)
: s{str}
{}
// when derefercing the iterator at some point, it will just return
// the character value at this position
charoperator*() const { return *s; }
// incrementing the iterator just increments the position in the string
cstring_iterator& operator++() {
++s;
return *this;
}
// compare iterators with sentinals
booloperator!=(const cstring_iterator_sentinel) const {
return s != nullptr && *s != '\0';
}
};
// so that a range-base for loop can be used
class cstring_range {
constchar *s {nullptr};
public:
cstring_range(constchar *str)
: s{str}
{}
// return a normal cstring_iterator from the begin function
cstring_iterator begin() const { return cstring_iterator{s}; }
// returns a sentinel type
cstring_iterator_sentinel end() const { return {}; }
};
int main(int argc, char *argv[])
{
if (argc != 2) {
std::cout << "Please provide one parameter.\n";
return 1;
}
constchar * const param {argv[1]};
for (char c : cstring_range(param)) {
std::cout << c;
}
std::cout << '\n';
return 0;
}
The program below does not allow me to enter argv. it goes directly to line 58. How come?
How did you ran it ?
Have a look at the error messages:
1 2 3 4 5 6 7 8 9 10 11
65:38: error: inconsistent begin/end types in range-based 'for' statement: 'cstring_iterator' and
'cstring_iterator_sentinel'
65:38: error: conversion from 'cstring_iterator_sentinel' to non-scalar type 'cstring_iterator'
requested
65:38: error: no match for'operator!=' (operand types are 'cstring_iterator' and 'cstring_iterator')
65:38: note: candidate is: 35:10: note: bool cstring_iterator::operator!=
(cstring_iterator_sentinel) const 35:10: note: no known conversion for argument 1 from
'cstring_iterator' to 'cstring_iterator_sentinel'
Yes. It requires support for the current standard (C++17).
As of C++17, the types of the begin_expr and the end_expr do not have to be the same, and in fact the type of the end_expr does not have to be an iterator: it just needs to be able to be compared for inequality with one. This makes it possible to delimit a range by a predicate (e.g. "the iterator points at a null character"). http://en.cppreference.com/w/cpp/language/range-for
With C++17 support enabled, compiles (and runs) cleanly with:
g++ 7.3.0 (FreeBSD and MinGW/Windows),
clang++ 5.0.1 (FreeBSD and MinGW/Windows),
g++ 7.2.0 (coliru/Linux) and
Visual Studio 2017 15.5.4 (v141/Windows)
Fails with:
clang++ 3.8.0 (coliru/Linux) and
the clang++ front end v141_clang_c2 (Visual Studio)
Although it worked from the Command Prompt, there must be a way it works from the IDE. Is there a way the argument for argv be inserted through the properties page?
Right click on your project name in Solution Explorer and select Properties.
Select Debug tab on the left. (Maybe Start Options, depending on the version)
Enter your parameters in Command Line Arguments textbox.
If you are using Visual Studio, in the Project Properties dialog, on the Debugging section you have the "Command arguments" setting, which lets you specify the arguments to pass when debugging the program from the IDE.