about
Bits Iter C++
05/31/2023
Bits Repo Code Bits Repo Docs

Bits_Iter C++

code, output, and build for C++ on Windows, macOS, and Linux

This page is a prototype used to decide which language features to emphasize. It will be replaced with a final version soon.

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() and end() methods which return iterators pointing to the first and one past the last element of the container.
Demo Notes  
All of the languages covered in this demonstration support iteration using iterators. C++ iterators are provided by enumerable containers and have a public interface similar to, but smaller than native pointers. Any operation that moves data under an iterator, like insertion, causes invalidation and any subsequent dereference operation will throw an exception. User-defined types can also provide iterators, as shown in the example code below.
The examples below show how to use library and user defined types with emphasis on illustrating iteration through container elements.

1.0 CodeSnaps

Source Code - Bits_Iter.cpp

/*-------------------------------------------------------------------
  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 <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 "AnalysisIter.h"   // Analysis functions
#include "PointsIter.h"     // PointN<T> class declaration
/*
  This demo uses the std::string and std::vector<T> classes
  and a user-defined class, PointN<T>, to illustrate how
  types support indexing and iteration.

  Operations:
    All the classes discussed here provide operations for:
      T t2 = t1          // copy construction
      T t3 = temporary   // move construction
      t1 = t2            // copy assignment
      t3 = temporary     // move assignment

    All instances return their resources when they go out of
    scope by implicitly calling their destructor.
    Primitive types can all be copied.

    Most library and user-defined types can be copied, moved,
    and deleted by providing member constructors and destructor.
    Often compiler generation works well, but for classes with
    pointer members developers must provide them.

  Processing:
    All types are static, operations run as native code, and no
    garbage collection is needed. Resources are returned at end
    of their declaration scope.
*/
#pragma warning(disable: 4984)  // warns about C++17 extension

/*-----------------------------------------------
  alias type name
  - pU<T> is the same type as std::unique_ptr<T>
  - this just provides a shorter name
*/
template<typename T>
using pU = std::unique_ptr<T>;

/*-----------------------------------------------
  forLoopVec accepts std::vector<T> instances
  by constant reference.
  - uses range-for to display PointN coordinates
*/
template<typename T>
void forLoopVec(const std::vector<T>& v) {
  std::cout << "\n    ";
  for(auto const &item : v) {
    std::cout << item << " ";
  }
}
/*-----------------------------------------------
  forLoopPoint accepts PointN<T> instances
  by constant reference.
  - uses range-for to display PointN coordinates
*/
template<typename T>
void forLoopPoint(const PointN<T>& p) {
    std::cout << "\n    ";
    for(auto const &item : p) {
      std::cout << item << " ";
    }
}
/*-----------------------------------------------
  whilerPoint accepts PointN<T> instances
  by constant reference.
  - uses iterator to display PointN coordinates
*/
template<typename T>
void whilerPoint(const PointN<T>& p) {
  auto itr = p.begin();
  std::cout << "\n    " << *itr++;
  while (itr < p.end()) {
    std::cout << ", " << *itr++;
  }
}
/*-----------------------------------------------
  whiler is flexible function that accepts any
  iterable container
  - will use iterator on C.
*/
template<typename C>
void whiler(const C& c) {
  auto itr = c.begin();  // uses const overload
  std::cout << "\n    " << *itr++;
  while (itr != c.end()) {
    std::cout << ", " << *itr++;
  }
}
/*-----------------------------------------------
  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 whiler_guarded(
  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\n";
    return;
  }
  else {
    std::cout << formatColl(c, name, "", indent, max);
    /*
      Analysis::formatColl uses range-based for loop to iterate
      over collection.
    */
  }
}
/*-------------------------------------------------------------------
  Demonstration starts here
*/
void testFormat();

int main() {

    print("Demonstrate C++ Iteration\n");

    showNote("std library types string and vector<T>");
    /* create and display std::string object */
    auto str = std::string("\"Wile E. Coyote\"");
    auto out = std::string("contents of str = ") + str;
    print(out);
    print("--- showType(str, \"str\"); ---");
    showType(str, "str", nl);

    showNote("Iterate over string");
    whiler_guarded(out, "out");
    print();

    /* create and display std::vector<double> */
    auto vec = std::vector<double>{ 3.5, 3, 2.5, 2 };
    std::cout << vec;
    showOp("showType(vec, \"vec\");");
    showType(vec, "vec", nl);

    showOp("vec[2] = -2.5;");
    vec[2] = -2.5;
    std::cout << "\n  vec:" << vec;

    showOp("auto vec2 = vec : copy construction");
    /* copy construction */
    auto vec2 = vec;
    std::cout << "\n  vec2:" << vec2;

    showOp("vec2[0] = 42;");
    vec2[0] = 42;
    std::cout << "\n  vec2: " << vec2;
    std::cout << "\n  vec: " << vec;

    showNote(
      "Copy construction, auto vec2 = vec, creates\n    "
      "independent instance. So changing target vec2\n    "
      "has no affect on source vec."
    );

    showNote(
      "Iterate over vector"
    );
    showOp("function using range-for taking vector");
    forLoopVec(vec);
    showOp("function using iterator taking iterable container");
    whiler(vec);
    print();

    showNote("user-defined type PointN<T>");

    PointN<double> p1(5);
    p1.show("p1");

    showNote(
      "p1.coords() = std::vector<double>\n    "
      "{ 1.0, -2.0, 3.0, 4.5, -42.0 }"
    );
    p1.coords() = std::vector<double>{1.0, -2.0, 3.0, 4.5, -42.0 };
    p1.show("p1");
    #pragma region
    showOp("showType(p1, \"p1\", nl);");
    showType(p1, "p1", nl);
    std::cout << "  p1.coords()[2] = " << p1.coords()[2] << "\n";

    showNote(
      "iterate over PointN<T>"
    );
    showOp("function using range-for taking Point");
    forLoopPoint(p1);
    showOp("function using iterator taking Point");
    whilerPoint(p1);
    showOp("function using iterator taking iterable container");
    whiler_guarded(p1, "p1");
    showOp("same function attempting to take non-iterable");
    struct S { int i; };
    auto s = S{3};
    whiler_guarded(s, "s");
    print();

    showNote("heap-based string instance");

    /* standard library type std::string */
    /* uses alias pU for std::unique_ptr, defined above */
    showOp(
      "pU<std::string> "
      "pStr(new std::string(\"\\\"Road Runner\\\"\")"
    );
    pU<std::string> pStr(new std::string("\"Road Runner\""));
    std::cout << "\n  pStr contents = " << *pStr << "\n";

    showOp("showType(*pStr, \"*pStr\")");
    showType(*pStr, "*pStr", nl);

    /* std::unique_ptr<T> cannot be copied but can be moved */
    showOp("showType(move(pStr), \"pStr\")");
    showType(move(pStr), "pStr", nl);

    /* standard library type std::vector<T> */
    showNote("heap-based vector instance");
    showOp(
      "pU<std::vector<double>>\n "
      "     pVec(new std::vector<double>{ 1.5, 2.5, 3.5 });"
    );
    pU<std::vector<double>> pVec(
      new std::vector<double>{ 1.5, 2.5, 3.5 }
    );
    print();
    showOp("iterating over *pVec");
    whiler_guarded(*pVec, "*pVec");
    print();
    std::cout << "\n  *pVec = " << *pVec;
    showType(*pVec, "*pVec", nl);
    std::cout << "\n  pVec = " << pVec;
    showType(move(pVec), "move(pVec)", nl);

    /* custom point type */

    showNote("heap-based PointN instance");

    showOp("pU<PointN<double>> pPointN(new PointN<double>(4))");
    pU<PointN<double>> pPointN(new PointN<double>(4));
    pPointN->show("*pPointN");

    showOp(
      "pPointN->coords() = \n"
      "      std::vector<double>{ 1.0, 3.5, -2.0, 42.0 };"
    );
    pPointN->coords() = std::vector<double>{ 1.0, 3.5, -2.0, 42.0 };
    pPointN->show("*pPointN");
    std::cout << "\n  value of pPointN->coords()[1] is "
              << pPointN->coords()[1];

    showOp("showType(*pPointN, \"*pPointN\");");
    showType(*pPointN, "*pPointN");
    print();

    showOp("iterating over *pPointN");
    whiler_guarded(*pPointN, "*pPointN");
    print();

    showOp("showType(std::move(pPointN), \"pPointN\");");
    showType(std::move(pPointN), "pPointN");
    /* pPointN moved, so now invalid */
    print();

    showNote(
      "Iterate over map, using Analysis::format"
    );

    std::map<std::string, int> map{{"zero", 0}, {"one", 1}};
    map.insert({"two", 2});
    std::cout << format(map, "map");

    // #define TEST
    #ifdef TEST
    testFormat();
    #endif

    print("\n  That's all Folks!\n\n");
}

void testFormat() {

  showNote("Test and demonstrate formatting functions");

  showOp("demonstrate PointN show()");
  print("default indent = 4 and width = 7:");
  PointN<int> p2(15);
  p2.show("p2");
  size_t saveLeft = p2.left();
  size_t saveWidth = p2.width();
  print("\n  indent = 6, width = 12:");
  p2.left() = 6;
  p2.width() = 12;
  p2.show("p2");

  showOp(
    "demonstrate operator<< overload for PointN ---"
  );
  p2.left() = saveLeft;
  p2.width() = saveWidth;
  print("default indent = 4 and width = 7:");
  std::cout << p2;
  print("\n  indent = 6, width = 12:");
  p2.left() = 6;
  p2.width() = 12;
  std::cout << p2;

  showOp(
    "demonstrate operator<< overload for vector"
  );
  auto vtest = std::vector<int>{1, 2, 3, 4, 5, 6, 7, 8, 9 };
  print("default indent = 4 and width = 7:");
  std::cout << vtest;
  DisplayParams.left = 2;
  DisplayParams.width = 5;
  print("indent = 2, width = 5:");
  std::cout << vtest;

  std::cout << formatColl(vtest, "vtest", nl, 2, 5);
  std::cout << formatColl(vtest, "vtest", nl, 4, 7);
  std::cout << formatColl(vtest, "vtest", nl, 2, 9);
  std::cout << formatColl(vtest, "vtest: vector<int>", nl, 2, 10);

  std::array<double, 5> arrtest = { 1, 2, 3, 4.5, -3.14159 };
  std::cout << formatColl(arrtest, "arrtest", nl, 2, 4);

  std::map<int, std::string> amap {
    {1, "one"}, {2, "two"}, {3, "three"}
  };
  std::cout << formatColl(amap, "amap", nl, 2, 4);

  std::set<std::string> aset {
    "one", "two", "three", "four", "five"
  };
  std::cout << formatColl(aset, "aset", nl, 2, 4);

  std::string astring = "this is a string";
  std::cout << formatString(astring, "astring", nl, 2);

  double adouble { 3.1415927 };
  std::cout << formatScalar(adouble, "adouble", nl);

  showNote("Using consolidated format function", nl);

  std::cout << format(adouble, "adouble", nl);
  std::cout << format(astring, "astring", nl);
  std::vector<double> avec{ 1, 2, 3, 4.5, -3.14159 };
  std::cout << format(avec, "avec", nl);
  std::cout << format(amap, "amap", nl);
}
          

Source Code - PointsIter.h

/*-------------------------------------------------------------------
  PointsIter.h defines point class PointN<T>
  - PointN<T> represents points with many coordinates of
    unspecified type T
  - Added iterator, begin(), end()
*/
#include <iostream>
#include <vector>
/*-------------------------------------------------------------------
  PointN<T> 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.

  Its default constructor PointN() is declared delete so it won't
  be provided here nor generated by the compiler.

  It provides iterators and begin() and end() members.
  These are used for iterating over PointN<T>'s elements.
*/
template<typename T>
class PointN {
public:
  using iterator = typename std::vector<T>::iterator;
  using const_iterator = typename std::vector<T>::const_iterator;
  using value_type = T;

  PointN() = delete;                              // default ctor
  PointN(size_t N);
  PointN(const PointN& pt) = default;             // copy ctor
  PointN(PointN&& pt) = default;                  // move ctor
  PointN& operator=(const PointN& pt) = default;  // copy assignment
  PointN& operator=(PointN&& pt) = default;       // move assignemnt
  ~PointN() = default;                            // dtor

  iterator begin();
  iterator end();
  const_iterator begin() const;
  const_iterator end() const;
  size_t size() const;
  T& operator[](size_t index);
  T operator[](size_t index) const;

  void push_back(T r);
  T pop_back();
  std::vector<T>& coords() { return coord; }

  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;
  size_t _left = 2;   // default display indent
  size_t _width = 7;  // default display row width
};
/*-----------------------------------------------
  PointN<T> constructor with size
*/
template<typename T>
PointN<T>::PointN(size_t N) {
  for(size_t i=0; i<N; i++) {
    coord.push_back(T{0});
  }
}
template<typename T>
size_t PointN<T>::size() const {
  return coord.size();
}
template<typename T>
T& PointN<T>::operator[](size_t index) {
  if (index < 0 || coord.size() <= index) {
    throw "indexing error";
  }
  return coord[index];
}
template<typename T>
T PointN<T>::operator[](size_t index) const {
  if (index < 0 || coord.len() <= index) {
    throw "indexing error";
  }
  return coord[index];
}
template<typename T>
typename PointN<T>::iterator PointN<T>::begin() {
  return coord.begin();
}
template<typename T>
typename PointN<T>::iterator PointN<T>::end() {
  return coord.end();
}
template<typename T>
typename PointN<T>::const_iterator PointN<T>::begin() const {
  return coord.begin();
}
template<typename T>
typename PointN<T>::const_iterator PointN<T>::end() const {
  return coord.end();
}
template<typename T>
void PointN<T>::push_back(T t) {
  coord.push_back(t);
}
template<typename T>
T PointN<T>::pop_back() {
  return coord.pop_back();
}
/*-----------------------------------------------
  PointtN<T> display function
*/
template<typename T>
void PointN<T>::show(const std::string& name) {
  std::cout << "\n" << indent(_left) << name << ": " << "PointN<T>";
  std::cout << " {\n";
  std::cout << fold(coord, _left + 2, _width);
  std::cout << indent(_left) << "}";
}
/*-----------------------------------------------
  Overload operator<< required for
  showType(PointN<T> t, const std::string& nm)
*/
template<typename T>
std::ostream& operator<<(std::ostream& out, PointN<T>& t2) {
  out << "\n" << indent(t2.left()) << "PointN<T>";
  out << " {\n";
  out << fold(t2.coords(), t2.left() + 2, t2.width());
  out << indent(t2.left()) << "}";
  return out;
}
          

Source Code - AnalysisIter.h

/*-------------------------------------------------------------------
  AnalysisIter.h
  - Provides functions that analyze types, display results
    and other program defined information.
  - Some of this code requires complex template operations.
    Those will be discussed in the generics bit.
  - You can skip the hard parts until then, without loss
    of understanding.
*/

#include <typeinfo>     // typeid
#include <utility>      // move()
#include <sstream>      // stringstream
#include <type_traits>  // is_scalar, if constexpr
#include <iostream>     // cout
#include <vector>       // vector

/*-------------------------------------------------------------------
  Analysis function declarations are provided here so that
  definitions below may be placed in any order. That's
  needed because C++ requires declaration before use.
*/
template<typename T>
void showType(T t, const std::string &nm, const std::string& suffix = "");
void showNote(const std::string& txt, const std::string& suffix = "");
void showOp(const std::string& opstr, const std::string& suffix = "");
void print(const std::string& txt = "");
void println(const std::string& txt = "");
std::string truncate(size_t N, const char* pStr);
std::string indent(size_t n);
template<typename T>
std::string fold(std::vector<T>& v, size_t left, size_t width);
template<typename T>
std::string formatColl(
  const T& t, const std::string& nm,
  const std::string& suffix = "", size_t left = 2, size_t width = 7
);
template<typename T>
std::string formatScalar(
  const T& t, const std::string& nm,
  const std::string& suffix = "", size_t left = 2
);
template<typename T>
std::string formatString(
  const T& t, const std::string& nm, const std::string& suffix,
  size_t left = 2
);
template<typename T>
std::string format(
  const T& t, const std::string& nm, const std::string& suffix = "",
  size_t left = 2, size_t width = 7
);

/* end of function declarations
-------------------------------------------------------------------*/

/*-------------------------------------------------------------------
  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 std::string& suffix) {
  print("--------------------------------------------------");
  print("  " + txt);
  print("--------------------------------------------------");
  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(int 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.
*/
template<typename Coll>
std::string formatColl(
  const Coll& c, const std::string& nm, const std::string& suffix,
  size_t left, size_t width
) {
  std::stringstream out;
  out << "\n" << indent(left) << nm << ": {\n" << indent(left + 2);
  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 << "\n" << indent(left) << "}" << 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";
}
          

Output

C:\github\JimFawcett\Bits\Cpp\Cpp_Iter\build
> debug/Cpp_Iter

  Demonstrate C++ Iteration

  --------------------------------------------------
    std library types string and vector<T>
  --------------------------------------------------
  contents of str = "Wile E. Coyote"
  --- showType(str, "str"); ---
  str type: class std::basic_string<char,struct std:...
  size:  40

  --------------------------------------------------
    Iterate over string
  --------------------------------------------------
  out: {
    c, o, n, t, e, n, t, s,
     , o, f,  , s, t, r,  ,
    =,  , ", W, i, l, e,  ,
    E, .,  , C, o, y, o, t,
    e, "
  }

  vector<T>: {
    3.5, 3, 2.5, 2
  }
  --- showType(vec, "vec"); ---
  vec type: class std::vector<double,class std::allo...
  size:  32

  --- vec[2] = -2.5; ---
  vec:
  vector<T>: {
    3.5, 3, -2.5, 2
  }
  --- auto vec2 = vec : copy construction ---
  vec2:
  vector<T>: {
    3.5, 3, -2.5, 2
  }
  --- vec2[0] = 42; ---
  vec2:
  vector<T>: {
    42, 3, -2.5, 2
  }
  vec:
  vector<T>: {
    3.5, 3, -2.5, 2
  }
  --------------------------------------------------
    Copy construction, auto vec2 = vec, creates
    independent instance. So changing target vec2
    has no affect on source vec.
  --------------------------------------------------
  --------------------------------------------------
    Iterate over vector
  --------------------------------------------------
  --- function using range-for taking vector ---
    3.5 3 -2.5 2
  --- function using iterator taking iterable container ---
    3.5, 3, -2.5, 2

  --------------------------------------------------
    user-defined type PointN<T>
  --------------------------------------------------
  p1: PointN<T> {
    0, 0, 0, 0, 0
  }
  --------------------------------------------------
    p1.coords() = std::vector<double>
    { 1.0, -2.0, 3.0, 4.5, -42.0 }
  --------------------------------------------------
  p1: PointN<T> {
    1, -2, 3, 4.5, -42
  }
  --- showType(p1, "p1", nl); ---
  p1 type: class PointN<double>
  size:  48
  p1.coords()[2] = 3

  --------------------------------------------------
    iterate over PointN<T>
  --------------------------------------------------
  --- function using range-for taking Point ---
    1 -2 3 4.5 -42
  --- function using iterator taking Point ---
    1, -2, 3, 4.5, -42
  --- function using iterator taking iterable container ---
  p1: {
    1, -2, 3, 4.5, -42
  }
  --- same function attempting to take non-iterable ---
  whiler input type is not iterable


  --------------------------------------------------
    heap-based string instance
  --------------------------------------------------
  --- pU<std::string> pStr(new std::string("\"Road Runner\"") ---
  pStr contents = "Road Runner"

  --- showType(*pStr, "*pStr") ---
  *pStr type: class std::basic_string<char,struct std:...
  size:  40

  --- showType(move(pStr), "pStr") ---
  pStr type: class std::unique_ptr<class std::basic_s...
  size:  8

  --------------------------------------------------
    heap-based vector instance
  --------------------------------------------------
  --- pU<std::vector<double>>
      pVec(new std::vector<double>{ 1.5, 2.5, 3.5 }); ---

  --- iterating over *pVec ---
  *pVec: {
    1.5, 2.5, 3.5
  }

  *pVec =
  vector<T>: {
    1.5, 2.5, 3.5
  }
  *pVec type: class std::vector<double,class std::allo...
  size:  32

  pVec = 000002965C6829B0
  move(pVec) type: class std::unique_ptr<class std::vector<...
  size:  8

  --------------------------------------------------
    heap-based PointN instance
  --------------------------------------------------
  --- pU<PointN<double>> pPointN(new PointN<double>(4)) ---
  *pPointN: PointN<T> {
    0, 0, 0, 0
  }
  --- pPointN->coords() =
      std::vector<double>{ 1.0, 3.5, -2.0, 42.0 }; ---
  *pPointN: PointN<T> {
    1, 3.5, -2, 42
  }
  value of pPointN->coords()[1] is 3.5
  --- showType(*pPointN, "*pPointN"); ---
  *pPointN type: class PointN<double>
  size:  48

  --- iterating over *pPointN ---
  *pPointN: {
    1, 3.5, -2, 42
  }

  --- showType(std::move(pPointN), "pPointN"); ---
  pPointN type: class std::unique_ptr<class PointN<doubl...
  size:  8

  --------------------------------------------------
    Iterate over map, using Analysis::format
  --------------------------------------------------
  map: {
    {one, 1}, {two, 2}, {zero, 0}
  }

  That's all Folks!

C:\github\JimFawcett\Bits\Cpp\Cpp_Iter\build
>
          

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
>
          

2.0 VS Code View

The code for this demo is available in github.com/JimFawcett/Bits. If you click on the Code dropdown you can clone the repository of all code for these demos to your local drive. Then, it is easy to bring up any example, in any of the languages, in VS Code. Here, we do that for Cpp\Cpp_Iter. Figure 1. VS Code IDE - Debug Cpp_Iter

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
  bottom refs VS Code bld out anal pts src codeSnaps top
  Next Prev Pages Sections About Keys