Beginner's Guide
    First Steps
    Input & Output
    Custom Types – Part 1
    Diagnostics
    Standard Library – Part 1
    Function Objects
    Standard Library – Part 2
    Code Organization
    Custom Types – Part 2
    Generic Programming
    Memory Management
    Software Design Basics

    Standard Library Numeric Operations Numeric Operations Numeric Ops

    produce one result based on a sequence of input elements
    produce a sequence of results with the same number of elements as the input sequence

    iota (fill with ascending numbers) iota (fill ascending) iota

    std::vector<int> v;
    v.resize(9,0);
    // fill subrange (as shown in image)
    iota(begin(v)+2, begin(v)+7 );
    for(int x : v) { cout << x << ' '; }  // 0 0 1 2 3 4 5 0 0
    // fill entire vector
    iota(begin(v), begin(v), 3);
    for(int x : v) { cout << x << ' '; }  // 3 4 5 6 7 8 9 10 11

    reduce reduce

    The reduction operation must be associative and commutative, because the order in which it is applied is not guaranteed.

    std::vector<int> v {1,9,7,3,2,8};
    auto const sum = reduce(begin(v), end(v));  // 30
    auto const s47 = reduce(begin(v), end(v), 47);  // 77
    
    std::vector<double> w {2.0, 1.5, 3.0, 1.5}; auto const product = reduce(begin(w), end(w), 1.0, std::multiplies<>{}); // 13.5
    // execute in parallel: #include <execution> auto const psum = reduce(std::execution::par, begin(v), end(v));

    Make sure that the type of the initial value ω is either the same as the input elements' type or a type that can represent more values!

    // narrower initial value type might // lead to loss of information:
    std::vector<double> v {1.2, 2.4};                     
    auto const wtf = reduce(begin(v), end(v), 1);  
    cout << wtf;  // 4                    int ^
    
    auto const sum = reduce(begin(v), end(v), 1.0); cout << sum; // 4.6 double ^^^

    transform_reduce transform_reduce

    The reduction operation must be associative and commutative and the projection f must not have side effects / be stateful, because there is no guaranteed order in which they are applied.

    std::vector<int> v {3,2,4};
    auto f = [](int x) { return x*x; };
    auto const rf = transform_reduce(begin(v), end(v), 1, std::plus<>{}, f);  
    // rf = 1 + f(3) + f(2) + f(4) = 30

    Both operations and must be associative and commutative because there is no guaranteed order in which they are applied.

    std::vector<double> x {1.0, 3.0, 5.0};
    std::vector<double> y {2.0, 4.0, 8.0};
    auto const rx1 = transform_reduce(begin(x), end(x), begin(y), 10.0);  
    // rx1 = 10 + (1⋅2)+(3⋅4)+(5⋅8) = 64
    auto const rx2 = transform_reduce(
        begin(x), end(x), begin(y), 0.0, 
        std::plus<>{}, std::divides<>{});  
    // rx2 = (1/2)+(3/4)+(5/8) = 1.875

    accumulate (≈ reduce) accumulate

    Prefer C++17's std::reduce because it can also be executed in parallel.

    std::vector<int> v {1,9,7,3,2,8};
    auto const sum = accumulate(begin(v), end(v), 0);  // 30
    auto const s47 = accumulate(begin(v), end(v), 47);  // 77
    
    std::vector<double> w {2.0, 1.5, 3.0, 1.5}; auto const product = accumulate(begin(w), end(w), 1.0, std::multiplies<>{}); // 13.5

    Make sure that the type of the initial value ω is either the same as the input elements' type or a type that can represent more values!

    // narrower initial value type might // lead to loss of information:
    std::vector<double> v {1.2, 2.4};                     
    auto const wtf = accumulate(begin(v), end(v), 0);  
    cout << wtf;  // 3                  int ^
    
    auto const sum = accumulate(begin(v), end(v), 0.0); cout << sum; // 3.6 double ^^^

    inner_product (≈ transform_reduce) inner_product

    Prefer C++17's std::transform_reduce because it can also be executed in parallel.

    std::vector<int> v {4,3,2,1};
    std::vector<int> w {10,20,30,40};
    auto const ip = inner_product(begin(v), end(v), begin(w), 50);  
    // ip = 50 + (4⋅10)+(3⋅20)+(2⋅30)+(1⋅40) = 250
    
    std::vector<double> num {1.0, 3.0, 5.0}; std::vector<double> den {2.0, 4.0, 8.0}; auto const res = inner_product( begin(num)end(num), begin(den), 0.0, std::plus<>{}, std::divides<>{} ); // res = (1/2)+(3/4)+(5/8) = 1.875

    This means that, e.g., target containers must be resized properly.

    Standard algorithms don't – and in most cases can't – check if the target range is large enough.

    Trying to copy elements beyond the target's capacity will invoke undefined behavior!

    adjacent_difference adjacent_difference

    The operation must not have side effects / be stateful, because the order in which it is applied is not guaranteed.

    std::vector<int> in {1,2,6,8,3,6};
    // make sure output can fit results
    std::vector<int> out;
    out.resize(in.size());
    adjacent_difference(begin(in), end(in), begin(out));
    for(int x : out) { cout << x << ' '; }  // 1 1 4 2 -5 3
    
    // C++17: can supply custom operation adjacent_difference(begin(in), end(in), begin(out), std::plus<>{}); for(int x : out) { cout << x << ' '; } // 1 3 8 14 11 9 adjacent_difference(begin(in), end(in), begin(out), std::multiplies<>{}); for(int x : out) { cout << x << ' '; } // 1 2 12 48 24 18

    inclusive_scan inclusive_scan

    The binary operation must be associative and commutative, because the order in which it is applied is not guaranteed.

    std::vector<int> in {2,1,7,5,3};
    // make sure output can fit results
    std::vector<int> out;
    out.resize(in.size());
    inclusive_scan(begin(in), end(in), begin(out));
    for(int x : out) { cout << x << ' '; }  // 2 3 10 15 18
    inclusive_scan(begin(in), end(in), begin(out), std::minus<>{});
    for(int x : out) { cout << x << ' '; }  // 2 1 -6 -11 -14
    // with offset '3':
    inclusive_scan(begin(in), end(in), begin(out), std::plus<>{}, 3);
    for(int x : out) { cout << x << ' '; }  // 5 6 13 18 21

    exclusive_scan exclusive_scan

    The binary operation must be associative and commutative because the order in which it is applied is not guaranteed.

    std::vector<int> in {2,1,7,5,3};
    // make sure output can fit results
    std::vector<int> out;
    out.resize(in.size());
    exclusive_scan(begin(in), end(in), begin(out), 0);
    for(int x : out) { cout << x << ' '; }  // 0 2 3 10 15
    // with offset '3':
    exclusive_scan(begin(in), end(in), begin(out), 3);
    for(int x : out) { cout << x << ' '; }  // 3 5 6 13 18
    exclusive_scan(begin(in), end(in), begin(out), 0, std::minus<>{});
    for(int x : out) { cout << x << ' '; }  // 0 -2 -3 -10 -15

    transform_inclusive_scan transform_inclusive_scan

    The operation must be associative and commutative and the projection f must not have side effects / be stateful, because the order in which they are applied is not guaranteed.

    // returns value only if even and 0 if odd
    auto even_only = [](int x) { return (x & 1) ? 0 : x; };
    std::vector<int> in {2,1,6,4,3};
    // make sure output can fit results
    std::vector<int> out;
    out.resize(in.size());
    transform_inclusive_scan(
      begin(in), end(in), begin(out), std::plus<>{}, even_only);
    for(int x : out) { cout << x << ' '; }  // 2 2 8 12 12
    // with offset '3':
    transform_inclusive_scan(
      begin(in), end(in), begin(out), std::plus<>{}, even_only, 3);
    for(int x : out) { cout << x << ' '; }  // 5 5 11 15 15
    // with projection f(x) = -x2:
    transform_inclusive_scan(
      begin(in), end(in), begin(out), std::plus<>{}, 
      [](int x) { return -(x*x); });
    for(int x : out) { cout << x << ' '; }  // -4 -5 -41 -57 -66

    transform_exclusive_scan transform_exclusive_scan

    The operation must be associative and commutative and the projection f must not have side effects / be stateful, because the order in which they are applied is not guaranteed.

    // returns value only if even and 0 if odd
    auto even_only = [](int x) { return (x & 1) ? 0 : x; };
    std::vector<int> in {2,1,6,4,3};
    // make sure output can fit results
    std::vector<int> out;
    out.resize(in.size());
    transform_exclusive_scan(
      begin(in), end(in), begin(out), 0, std::plus<>{}, even_only);
    for(int x : out) { cout << x << ' '; }  // 0 2 2 8 12
    // with offset '3':
    transform_exclusive_scan(
      begin(in), end(in), begin(out), 3, std::plus<>{}, even_only);
    for(int x : out) { cout << x << ' '; }  // 3 5 5 11 15
    // with projection f(x) = -x2:
    transform_exclusive_scan(
      begin(in), end(in), begin(out), 0, std::plus<>{}, 
      [](int x) { return -(x*x); });
    for(int x : out) { cout << x << ' '; }  // 0 -4 -5 -41 -57

    partial_sum (≈ inclusive_scan) partial_sum

    Prefer C++17's std::inclusive_scan because it can also be executed in parallel.

    std::vector<int> in {1,1,2,2,1,1};
    // make sure output can fit results
    std::vector<int> out;
    out.resize(in.size());
    partial_sum(begin(in), end(in), begin(out));
    for(int x : out) { cout << x << ' '; }  // 1 2 4 6 7 8
    partial_sum(begin(in), end(in), begin(out), std::minus<>{});
    for(int x : out) { cout << x << ' '; }  // 1 0 -2 -4 -5 -6