about
Bits Iter C++
06/16/2024
0
Bits: C++ Iteration
indexing into and iteration through std and user-defined collections
Synopsis:
This Bit demonstrates uses of C++ iterators to walk through enumerable collections. The purpose is to quickly acquire some familiarity with C++ iteration.- C++ Iterators are smart pointers that are provided by, and have special knowledge about the structure of, C++ iterable containers.
-
An iterable C++ container provides
begin() andend() methods which return iterators pointing to the first and one past the last element of the container.
Demo Notes
1.0 Iterators
Table 1. - Basic Iterator Operations
|
returns iterator pointing to the first element of |
|
returns iterator pointing to one past the last element of |
iter++; val = *iter; |
After executing this code
iter points to the second element of |
/* do something with item */ } |
range-for extracts iterator from { /* do some thing with *iter */ } |
2.0 Source Code
Source code for this bit can be found here: | Bits Iter C++ code |
All of the bits code is here: You can clone this repository and run all the examples locally. |
Bits code |
2.1 Basic Iteration
/*-----------------------------------------------
Basic iterator operations
- uses std::vector<int>
- could be any other iterable container
*/
void iteratorBasics() {
showOp("iterator basics");
std::cout << std::endl;
auto v = std::vector<int> { 1, 2, 3, 4, 5 };
/* basic loop showing iterator usage */
for(auto itr = v.begin(); itr != v.end(); ++itr) {
std::cout << *itr << " ";
}
std::cout << " - using basic for loop" << std::endl;
/* range-for uses iterator internally */
for(auto item : v) {
std::cout << item << " ";
}
std::cout << " - using range-for" << std::endl;
std::cout << std::endl;
int arr[5] { 1, 2, 3, 2, 1 };
/* basic loop showing iterator usage */
for(auto itr = std::begin(arr); itr != std::end(arr); ++itr) {
std::cout << *itr << " ";
}
std::cout << " - using basic for loop with native array" << std::endl;
/* range-for uses iterator internally */
for(auto item : arr) {
std::cout << item << " ";
}
std::cout << " - using range-for with native array" << std::endl;
std::cout << std::endl;
}
--- iterator basics ---
1 2 3 4 5 - using basic for loop
1 2 3 4 5 - using range-for
1 2 3 2 1 - using basic for loop with native array
1 2 3 2 1 - using range-for with native array
2.2 Iteration for Specified Collections
/*-----------------------------------------------
demoIndexer(const std::vector<T>& v)
- accepts std::vector<T>
- creates comma separated list
- uses indexing, not using iterator
*/
template<typename T>
void indexerVec(const std::vector<T>& v) {
if(v.size() < 1)
return;
std::cout << "\n " << v[0];
for(size_t i = 1; i<v.size(); ++i) {
std::cout << ", " << v[i];
}
}
void executeIndexerVec() {
std::cout << "\nexecute demoIndexerVec(v)";
auto v = std::vector<int> { 1, 2, 3, 2, 1 };
indexerVec(v);
}
/*-----------------------------------------------
demoIteratorVec
- accepts std::vector<T> instances
- uses iterator
*/
template<typename T>
void iteratorVec(const std::vector<T>& v) {
auto itr = v.begin();
std::cout << "\n " << *itr;
while(++itr != v.end()) {
std::cout << ", " << *itr;
}
}
void executeIteratorVec() {
std::cout << "\nexecute demoIteratorVec(v)";
auto v = std::vector<int> { 1, 2, 3, 2, 1 };
iteratorVec(v);
}
/*-----------------------------------------------
demoForLoopVec
- accepts std::vector<T> instances
- uses range-for to display elements
- that uses iterator implicitly
*/
template<typename T>
void forLoopVec(const std::vector<T>& v) {
std::cout << "\n ";
for(auto const &item : v) {
std::cout << item << " ";
}
}
void executeForLoopVec() {
std::cout << "\nexecute demoForLoopVec(v)";
auto v = std::vector<int> { 1, 2, 3, 2, 1 };
forLoopVec(v);
}
/*-----------------------------------------------
forLoopPoint
- accepts Point<T, N> instances by constant reference.
- uses range-for to display Point coordinates
- creates comma separated list
*/
template<typename T, const size_t N>
void forLoopPoint(const Point<T, N>& p) {
auto s = std::stringstream();
s << "\n ";
for(auto const &item : p) {
s << item << ", ";
}
auto str = s.str();
/* remove last ", " */
str.pop_back();
str.pop_back();
std::cout << str;
}
void executeForLoopPoint() {
std::cout << "\nexecute demoForLoopPoint(v)";
/* using initialization list */
auto p = Point<int, 5> { 1, 2, 3, 2, 1 };
forLoopPoint(p);
}
/*-----------------------------------------------
whilerPoint
- accepts Point<T, N> instances by constant reference.
- explicit use of iterator to display PointN coordinates
- creates comma separated list
*/
template<typename T, const size_t N>
void whilerPoint(const Point<T, N>& p) {
auto itr = p.begin();
std::cout << "\n " << *itr++;
while (itr < p.end()) {
std::cout << ", " << *itr++;
}
}
void executeWhilerPoint() {
std::cout << "\nexecute demoWhilerPoint(v)";
auto p = Point<int, 5>();
/* using indexer */
p[0] = 1;
p[1] = 2;
p[2] = 3;
p[3] = 2;
p[4] = 1;
whilerPoint(p);
}
--- collection specific iterations ---
execute indexerVec(v)
1, 2, 3, 2, 1
execute iteratorVec(v)
1, 2, 3, 2, 1
execute forLoopVec(v)
1 2 3 2 1
execute forLoopPoint(v)
1, 2, 3, 2, 1
execute whilerPoint(v)
1, 2, 3, 2, 1
2.3 Iteration for Generic Collections
/*-----------------------------------------------
demoWhiler
- is flexible function that accepts any
iterable container
- uses iterator on C.
- creates comma separated list
*/
template<typename C>
void demoWhiler(const C& c) {
auto itr = c.begin(); // uses const overload
std::cout << "\n " << *itr++;
while (itr != c.end()) {
std::cout << ", " << *itr++;
}
}
void executeDemoWhiler() {
std::cout << "\nexecute demoWhiler(c) with string";
auto s = std::string("a string");
demoWhiler(s);
std::cout << "\nexecute demoWhiler(c) with vector";
auto v = std::vector<double> { 1.0, 1.5, -1.5, -1.0, 0 };
demoWhiler(v);
std::cout << "\nexecute demoWhiler(c) with Point";
auto p = Point<double, 5> { 1.0, 2.0, 3.0, 2.0, 1.0 };
demoWhiler(p);
}
/*-----------------------------------------------
whiler_guarded is flexible function that accepts
any container
- if C is iterable will use iterator on C.
- If non-iterable input is detected,
will display error msg and return.
- decision is made at compile time.
- is_iterable_v is defined in Analysis.h
- max is the maximum number of items
to show on one line
*/
template<typename C>
void whilerGuarded(
const C& c, const std::string& name,
size_t indent = 2, size_t max = 8
) {
if constexpr(!is_iterable_v<C>) { // decision at compile-time
std::cout << "\n whiler input type is not iterable";
return;
}
else {
std::cout << formatColl(c, name, "", indent, max);
/*
Analysis::formatColl uses range-based for loop to iterate
over collection, folding output into rows of max items.
Could have used the same iteration as in demoWhiler
but wanted to show nicer formatting.
*/
}
}
void executeWhilerGuarded() {
std::cout << "\nexecute demoWhilerGuarded(c) with vector";
auto v = std::vector<int> { 1, 2, 3, 2, 1, 0, -1, -2, -3, -4 };
whilerGuarded(v, "vector");
std::cout << "\nexecute demoWhiler(c) with double";
whilerGuarded(3.5, "double");
auto v2 = std::vector<int> { 1, 2, 3, 4, 5 };
}
--- accepts any iterable collection ---
execute demoWhiler(c) with string
a, , s, t, r, i, n, g
execute demoWhiler(c) with vector
1.0, 1.5, -1.5, -1.0, 0.0
execute demoWhiler(c) with Point
1.0, 2.0, 3.0, 2.0, 1.0
--- detects non-iterable input at compile-time ---
execute demoWhilerGuarded(c) with vector
vector : {
1, 2, 3, 2, 1, 0, -1, -2,
-3, -4
}
execute demoWhiler(c) with double
whiler input type is not iterable
2.4 Point<T, N> Definition
/*-------------------------------------------------------------------
Point<T, N> class represents a point in an N-Dimensional hyperspace.
It uses a template parameter to support a variety of coordinate
types, and uses a vector to hold any finite number of
coordinates, specified by N.
It also carries a Time t instance which conceptually is the time
at which something was at that point in space. Time is a class
defined for this demonstration in Time.h.
All its special members, ctors, assignment, ... with the exception
of constructor Point(), are declared default to indicate to a maintainer
that compiler generated methods are correct and should not be provided.
It does not provide an iterator nor begin() and end() members.
Those will added in the iteration bit.
*/
template<typename T, const size_t N>
class Point {
public:
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;
using value_type = T;
Point(); // default ctor
Point(std::initializer_list<T> il); // construct from list
Point(const Point& pt) = default; // copy ctor
Point(Point&& pt) = default; // move ctor
Point& operator=(const Point& pt) = default; // copy assignment
Point& operator=(Point&& pt) = default; // move assignemnt
~Point() = default; // dtor
void init(const std::vector<T>& v);
std::string timeToString();
void updateTime();
Time& time();
const size_t size() const;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
T& operator[](size_t index); // index oper
const T operator[](size_t index) const; // const index oper
std::vector<T>& coords() { return coord; } // accessor
void show(const std::string& name); // display contents
size_t& left() { return _left; } // display indent
size_t& width() { return _width; } // display width
private:
std::vector<T> coord;
Time tm;
size_t _left = 2; // default display indent
size_t _width = 7; // default display row width
};
/*-----------------------------------------------
Point<T, N> constructor with size Template
parameter
*/
template<typename T, size_t N>
Point<T, N>::Point()
: tm(Time()) {
for(size_t i=0; i<N; i++) {
coord.push_back(T{0});
}
}
/*-----------------------------------------------
Fill coor with elements from initializer list li
- if li is smaller than N then fill remainder with
default values of T
- if li is larger use first N elements of li
*/
template<typename T, size_t N>
Point<T, N>::Point(std::initializer_list<T> il)
: tm(Time()) {
size_t sz = std::min(N, il.size());
size_t i = 0;
for(auto item : il) {
coord.push_back(item);
if(++i == sz) {
break;
}
}
for(size_t i = il.size(); i<N; i++) {
coord.push_back(T{0});
}
}
/*---------------------------------------------
Always returns N
*/
template<typename T, size_t N>
const size_t Point<T, N>::size() const {
return coord.size();
}
/*---------------------------------------------
index returns mutable value
*/
template<typename T, size_t N>
T& Point<T, N>::operator[](size_t index) {
if (index < 0 || coord.size() <= index) {
throw "Point<T, N> indexing error";
}
return coord[index];
}
/*---------------------------------------------
index returns immutable value
*/
template<typename T, size_t N>
const T Point<T, N>::operator[](size_t index) const {
if (index < 0 || coord.len() <= index) {
throw "Point<T, N> indexing error";
}
return coord[index];
}
template<typename T, const size_t N>
typename Point<T, N>::iterator Point<T, N>::begin() {
return coord.begin();
}
template<typename T, const size_t N>
typename Point<T, N>::iterator Point<T, N>::end() {
return coord.end();
}
template<typename T, const size_t N>
typename Point<T, N>::const_iterator Point<T, N>::begin() const {
return coord.begin();
}
template<typename T, const size_t N>
typename Point<T, N>::const_iterator Point<T, N>::end() const {
return coord.end();
}
/*-----------------------------------------------
Fill coor with elements from vector v
- if v is smaller fill remainder with default
values of T
- if v is larger use first N elements of v
*/
template<typename T, size_t N>
void Point<T, N>::init(const std::vector<T>& v) {
size_t sz = std::min(N, v.size());
for(size_t i=0; i<sz; i++) {
coord[i] = v[i];
}
for(size_t i = v.size(); i<N; i++) {
coord[i] = T{0};
}
}
/*---------------------------------------------
returns string datetime
*/
template<typename T, size_t N>
std::string Point<T, N>::timeToString() {
std::string ts = tm.toString();
return ts;
}
/*---------------------------------------------
set time to current time
*/
template<typename T, size_t N>
void Point<T, N>::updateTime() {
tm = std::time(0);
}
/*---------------------------------------------
returns current number of seconds in clock's
epoch
*/
template<typename T, size_t N>
Time& Point<T, N>::time() {
return tm;
}
/*-----------------------------------------------
PointtN<T> display function
*/
template<typename T, size_t N>
void Point<T, N>::show(const std::string& name) {
std::cout << "\n" << indent(_left) << name << ": " << "Point<T, N>";
std::cout << " {\n";
std::cout << fold(coord, _left + 2, _width);
std::cout << indent(_left) << "}";
std::cout << "\n" << indent(_left) << tm.toString() << std::endl;
}
/*-----------------------------------------------
Overload operator<< required for
showType(Point<T, N> t, const std::string& nm)
*/
template<typename T, size_t N>
std::ostream& operator<<(std::ostream& out, Point<T, N>& t2) {
out << "\n" << indent(t2.left()) << "Point<T, N>";
out << " {\n";
out << fold(t2.coords(), t2.left() + 2, t2.width());
out << indent(t2.left()) << "}";
return out;
}
2.5 Point<T, N> Demonstration
void demo_custom_type_Point_iteration() {
using namespace Analysis;
using namespace Points;
showNote("iteration over user-defined Point<T, N>", 45, "\n");
/*-- demonstrate Point<double 3> initialization lists --*/
showOp("Point<double, 3> p1 {1.0, 1.5, 2.0, 1.5, 1.0 }"); // equal to N
Point<double, 5> p1 {1.0, 1.5, 2.0, 1.5, 1.0};
p1.left() = 0;
p1.show("p1");
std::cout << "\np1[1] = " << p1[1]; // indexing
std::cout << "\np1.time().day() = "
<< p1.time().day();
std::cout << "\np1.time().seconds() = "
<< p1.time().seconds() << "\n";
showOp("iteration using basic loop", "\n");
auto itr = p1.begin();
while(true) {
std::cout << *itr++ << " ";
if(itr == p1.end()) {
break;
}
}
std::cout << std::endl;
showOp("iteration using range-for", "\n");
for(auto item : p1) {
std::cout << item << " ";
}
std::cout << std::endl;
showOp("Point<int, 10> p2 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }");
Point<int, 10> p2 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
p2.left() = 0;
p2.show("p2");
}
---------------------------------------------
iteration over user-defined Point
---------------------------------------------
--- Point p1 {1.0, 1.5, 2.0, 1.5, 1.0 } ---
p1: Point {
1, 1.5, 2, 1.5, 1
}
Tue Jun 18 09:25:11 2024 local time zone
p1[1] = 1.5
p1.time().day() = 18
p1.time().seconds() = 11
--- iteration using basic loop ---
1.0 1.5 2.0 1.5 1.0
--- iteration using range-for ---
1.0 1.5 2.0 1.5 1.0
--- Point p2 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } ---
p2: Point {
1, 2, 3, 4, 5, 6, 7,
8, 9, 10
}
Tue Jun 18 09:25:11 2024 local time zone
2.6 Analysis Functions
2.6 Analysis and Display Functions
/*-------------------------------------------------------------------
Display and Analysis function and globals definitions
---------------------------------------------------------------------
*/
const std::string nl = "\n";
/*-------------------------------------------------------------------
Mutable globals are a common source of bugs. We try not
to use them, but will use DisplayParams here to control how
the insertion operator sends instances to standard output.
*/
struct displayParams {
size_t left = 2; // number of spaces to indent
size_t width = 7; // width of display row
size_t trunc = 40; // replace text after trunc with ...
} DisplayParams; // global object
/*-----------------------------------------------
Overload operator<< required for
showType(std::vector<T> v, const std::vector<T>& nm)
*/
template<typename T>
std::ostream& operator<<(std::ostream& out, std::vector<T>& v) {
out << format(v, "vector<T>", "", DisplayParams.left, DisplayParams.width);
return out;
}
/*-----------------------------------------------
Display calling name, static class, and size
*/
template<typename T>
void showType(T t, const std::string &callname, const std::string& suffix) {
std::cout << "\n " << callname; // show name at call site
std::cout << " type: "
<< truncate(DisplayParams.trunc,typeid(t).name()); // show type
std::cout << "\n size: " << sizeof(t); // show size on stack
std::cout << suffix;
}
/*-----------------------------------------------
Display emphasized text
*/
inline void showNote(
const std::string& txt,
const size_t width,
const std::string& suffix
) {
auto fill = std::string(width, '-');
print(fill);
print(" " + txt);
print(fill);
std::cout << suffix;
}
/*-----------------------------------------------
Display emphasized line
*/
inline void showOp(const std::string& opstr, const std::string& suffix) {
std::cout << "\n--- " << opstr << " ---" << suffix;
}
/*-----------------------------------------------
Helper function for formatting output
- truncates line to N chars and adds ellipsis
*/
inline std::string truncate(size_t N, const char* pStr) {
std::string temp(pStr);
if(temp.length() > N) {
temp.resize(N);
return temp + "...";
}
return temp;
}
/*-----------------------------------------------
Helper function for formatting output
- generates string of n blanks to offset text
*/
inline std::string indent(size_t n) {
return std::string(n, ' ');
}
/*-----------------------------------------------
Helper function for formatting output
- folds lines after width elements
*/
template<typename T>
std::string fold(std::vector<T>& v, size_t left, size_t width) {
std::stringstream out("\n");
out << indent(left);
for(size_t i=0; i<v.size(); ++i) {
if((i % width) == 0 && i != 0 && i != width - 1) {
out << "\n" << indent(left);
}
if(i < v.size() - 1) {
out << v[i] << ", ";
}
else {
out << v[i] << "\n";
break;
}
}
return out.str();
}
/*-----------------------------------------------
Helper function for formatColl
- defines out << std::pair<K,V>
- used in formatColl for associative containers
*/
template<typename K, typename V>
std::stringstream& operator<<(
std::stringstream& out, const std::pair<K,V>& p
) {
out << "{" << p.first << ", " << p.second << "}";
return out;
}
/*-----------------------------------------------
Format output for Collection types
- any type with begin() and end() like
all the STL containers.
- if nm is larger than empty str displays nm : { + ...
- if nm is empty str displays { + ...
- if c.size() <= width displays on one line
- if c.size() > width displays on folded stack of lines
*/
template<typename Coll>
std::string formatColl(
const Coll& c, const std::string& nm = "", const std::string& suffix = "",
size_t left = 2, size_t width = 7
) {
std::string nameStr;
std::string prologue;
std::string epilogue;
if(nm.size() == 0) {
nameStr = "{ ";
}
else {
nameStr = nm + " : { ";
}
if(c.size() <= width) {
prologue = indent(left) + nameStr;
epilogue = " }";
}
else {
prologue = indent(left) + nameStr + "\n" + indent(left + 2);
epilogue = "\n" + indent(left) + "}\n";
}
std::stringstream out;
out << "\n" + prologue;
size_t i = 0;
for(const Coll::value_type& elem : c) {
if((i % width) == 0 && i != 0 && i != width - 1) {
out << "\n" << indent(left + 2);
}
if(i < c.size() - 1) {
out << elem << ", ";
}
else {
out << elem << epilogue << suffix;
break;
}
++i;
}
return out.str();
}
/*-----------------------------------------------
Format output for scalar types like primitives
*/
template<typename T>
std::string formatScalar(
const T& t, const std::string& nm, const std::string& suffix,
size_t left
) {
std::stringstream out;
out << "\n" << indent(left) << nm << ": " << t << suffix;
return out.str();
}
/*-----------------------------------------------
Format output for strings
- indent and embed in quotation marks
*/
template<typename T>
std::string formatString(
const T& t, const std::string& nm, const std::string& suffix,
size_t left
) {
std::stringstream out;
out << "\n" << indent(left) << nm << ": \"" << t << "\"" << suffix;
return out.str();
}
/*-----------------------------------------------
Defines is_iterable trait
- detects STL containers and user-defined types
that provide iteration
- uses template metaprogramming, e.g., user code
that runs at compile-time
https://stackoverflow.com/questions/13830158/check-if-a-variable-type-is-iterable
*/
template <typename T, typename = void>
struct is_iterable : std::false_type {};
// this gets used only when we can call
// std::begin() and std::end() on that type
template <typename T>
struct is_iterable<
T,
std::void_t
<decltype(std::begin(std::declval<T>())),
decltype(std::end(std::declval<T>()))>
> : std::true_type {};
template <typename T>
constexpr bool is_iterable_v = is_iterable<T>::value;
/*-----------------------------------------------
Displays almost everything.
- strings work better with formatString(...)
https://www.cppstories.com/2018/03/ifconstexpr/
Iteration is discussed in Bit Cpp_iter
*/
template<typename T>
std::string format(
const T& t, const std::string& nm, const std::string& suffix,
size_t left, size_t width
) {
if constexpr(is_iterable_v<T>) { // decision at compile-time
return formatColl(t, nm, suffix, left, width);
}
else {
return formatScalar(t, nm, suffix, left);
}
}
/*-----------------------------------------------
Display text after newline and indentation
*/
inline void print(const std::string& txt) {
std::cout << "\n " << txt;
}
/*-----------------------------------------------
Display text after newline and indentation
- provides trailing newline
*/
inline void println(const std::string& txt) {
std::cout << "\n " << txt << "\n";
}
Analysis and Display:
⇐std::vector<T> operator<< ⇐showType ⇐showNote ⇐showOp ⇐truncate ⇐indent ⇐fold ⇐std::pair<K,V> operator<< ⇐formatColl ⇐formatScalar ⇐formatString ⇐is_iterable ⇐format ⇐println
2.7 Program Structure
Code Structure
/*-------------------------------------------------------------------
Bits_Iter.cpp
- defines functions to iterate over collections
- depends on Points.h to provide user-defined point class
- depends on Analysis.h for several display and analysis functions
*/
#include <iostream> // std::cout
#include <iomanip> // std::fixed, std::setprecision
#include <sstream> // std::stringstream
#include <memory> // std::unique_ptr
#include <vector> // vector<T> class
#include <array> // array<T> class
#include <map> // map<K,V> class
#include <set> // set<T> class
#include <concepts> // supports C++20 concepts
#include <algorithm> // STL algorithms
#include "AnalysisIter.h" // Analysis functions
#include "PointsIter.h" // PointN<T> class declaration
using namespace Points;
/*-----------------------------------------------
Note:
Find all Bits code, including this in
https://github.com/JimFawcett/Bits
You can clone the repo from this link.
-----------------------------------------------*/
/*
This demo uses the std::string and std::vector<T> classes
and a user-defined class, Point<T, N>, to illustrate how
types support indexing and iteration.
- Each standard container, C, provides C::iterator,
C::const_iterator, C::reverse_iterator, and
begin() and end() methods that return iterators to
the first and one past the last element of the
collection, respectively.
*/
void iteratorBasics() {
/* code elided */
}
template<typename T>
void indexerVec(const std::vector<T>& v) {
/* code elided */
}
void executeIndexerVec() {
/* code elided */
}
template<typename T>
void iteratorVec(const std::vector<T>& v) {
/* code elided */
}
void executeIteratorVec() {
/* code elided */
}
template<typename T>
void forLoopVec(const std::vector<T>& v) {
/* code elided */
}
void executeForLoopVec() {
/* code elided */
}
template<typename T, const size_t N>
void forLoopPoint(const Point<T, N>& p) {
/* code elided */
}
void executeForLoopPoint() {
/* code elided */
}
template<typename T, const size_t N>
void whilerPoint(const Point<T, N>& p) {
/* code elided */
}
void executeWhilerPoint() {
/* code elided */
}
template<typename C>
void demoWhiler(const C& c) {
/* code elided */
}
void executeDemoWhiler() {
/* code elided */
}
template<typename C>
void whilerGuarded(
const C& c, const std::string& name,
size_t indent = 2, size_t max = 8
) {
/* code elided */
}
void executeWhilerGuarded() {
/* code elided */
}
template<typename C, typename F>
void forEachOp(C& c, F f) {
/* code elided */
}
void executeForEachOp() {
/* code elided */
}
template<typename C>
inline void showCSL(const C& c, const std::string& nm, size_t max, size_t indent) {
/* code elided */
}
void executeForEachAlgorithm() {
/* code elided */
}
/*-------------------------------------------------------------------
Demonstration starts here
*/
void testFormat();
int main() {
showNote("Demonstrate C++ Iteration", 30, "\n");
iteratorBasics();
showOp("collection specific iterations", nl);
std::cout << std::fixed;
std::cout << std::setprecision(1);
executeIndexerVec();
executeIteratorVec();
executeForLoopVec();
executeForLoopPoint();
executeWhilerPoint();
print();
showOp("accepts any iterable collection", nl);
executeDemoWhiler();
print();
showOp("detects non-iterable input at compile-time", nl);
executeWhilerGuarded();
print();
showOp("using lambda to operate on items", nl);
executeForEachOp();
std::cout << "\n";
showOp("using std::for_each algorithm to modify items", nl);
executeForEachAlgorithm();
demo_custom_type_Point_iteration();
// #define TEST
#ifdef TEST
testFormat();
#endif
print("\n That's all Folks!\n\n");
}
void testFormat() {
/* code elided */
}
Code Structure:
This program is partitioned into 3 header-only libraries and a demonstration file that uses them.
The libraries are: - PointsIter.h - Time.h, included in Points.Iter.h - AnalysisIter.h and the demonstration file is: - Bits_Iter.cpp
PointsIter.h: - definesPoint<N, T> - includes Time.h Time.h - definesTime andTimer types. AnalysisIter.h: - defines several functions used to analyze type instances and display them. Bits_IterCpp.cpp - includes the libraries - defines several demonstration functions, each of which demonstrates iteration techniques for types in std, std::library, and user-defined typePoint<T, N>
Each library declares at the beginning: #ifndef [libname] #define [libname] and at the end: #endif
That ensures that each header is only compiled once, avoiding multiple definitions and skipping unnec- essary compiles.
3.0 Build
C:\github\JimFawcett\Bits\Cpp\Cpp_Iter
> cd build
C:\github\JimFawcett\Bits\Cpp\Cpp_Iter\build
> cmake ..
-- Selecting Windows SDK version 10.0.22000.0 to target Windows 10.0.22621.
-- Configuring done
-- Generating done
-- Build files have been written to: C:/github/JimFawcett/Bits/Cpp/Cpp_Iter/build
C:\github\JimFawcett\Bits\Cpp\Cpp_Iter\build
> cmake --build .
MSBuild version 17.5.1+f6fdcf537 for .NET Framework
Checking Build System
Building Custom Rule C:/github/JimFawcett/Bits/Cpp/Cpp_Iter/CMakeLists.txt
Cpp_Iter.vcxproj -> C:\github\JimFawcett\Bits\Cpp\Cpp_Iter\build\Debug\Cpp_Iter.ex
e
Building Custom Rule C:/github/JimFawcett/Bits/Cpp/Cpp_Iter/CMakeLists.txt
C:\github\JimFawcett\Bits\Cpp\Cpp_Iter\build
>
4.0 VS Code View
3.0 References
Reference | Description |
---|---|
C++ Story: Standard Template Library | Covers containers, iterators, and STL algorithms |
C++ Story | E-book with thirteen chapters covering most of intermediate C++ |
C++ Bites | Relatively short feature discussions |
Point<T, N> Support for Iteration: