Search code examples
c++c++20

std::generate - access previous element in vector


I am using std::generate() to construct a struct and push it into a std::vector. In order to construct the struct, I need to refer to the previous struct in the sequence. Is there any way to do this in C++20? I would rather not use a 3rd party library, like boost.

#include <iostream>
#include <vector>
#include <algorithm>

struct CashFlow {

    double begin_balance;
    double payment;
    double interest;
    double prin_repayment;
    double end_balance;
    size_t month;

    friend std::ostream& operator<<(std::ostream& os, const CashFlow& cf);
};

std::vector<CashFlow> cashflows(n);   

//this is i = 0 struct
CashFlow c;
c.month = 0;
c.begin_balance = initial_prin;
c.end_balance = initial_prin;

cashflows.push_back(c);

std::generate(begin(cashflows) + 1, end(cashflows), [&, i = 1]() 
mutable {
    CashFlow c;
    c.month = i;
    //here I need end_balance member of the previous struct in the vector
    c.begin_balance = std::prev(cashflows.end()).end_balance; // this does not work
    c.payment = payment;
    c.end_balance = initial_prin * ((100 - pow(1 + 0.08, i)) / (100 - 1));
    c.interest = 0.08 * c.begin_balance;
    c.prin_repayment = 80 - c.interest;
    return c;
});

Solution

  • Your std::generate() lambda can simply store the previous generated value that you want to pass along to the next iteration, just like you are doing with i, eg:

    std::vector<CashFlow> cashflows(n);   
    
    //this is i = 0 struct
    CashFlow& initial_c = cashflows.front();
    initial_c.month = 0;
    initial_c.begin_balance = initial_prin;
    initial_c.end_balance = initial_prin;
    
    std::generate(begin(cashflows) + 1, end(cashflows),
        [&, i = 1, previous_end_balance = initial_prin]() mutable {
            CashFlow c;
            c.month = i;
            c.begin_balance = previous_end_balance;
            c.payment = payment;
            c.end_balance = initial_prin * ((100 - pow(1 + 0.08, i)) / (100 - 1));
            c.interest = 0.08 * c.begin_balance;
            c.prin_repayment = 80 - c.interest;
            previous_end_balance = c.end_balance;
            ++i;
            return c;
        }
    );