Search code examples
c++progress-barc++20evaluationstd-pair

Forcing evaluation order of `std::pair` constructors; a progress bar `struct` for a for-loop


I'm writing a program containing many long for-loops, and I want to add a progress bar indicator to each. To do this, I wrote struct ProgressBar to accomplish this. The interface is as follows:

struct ProgressBar {
    int start, end;  // starting and ending values of the loop variable
    const int &curr; // const reference to the loop variable

    /* Update the progress bar by inspecting the current value of "curr" */
    void update();

    /* Constructor; the reference "curr" is initialized in the member initializer list, as it must be */
    ProgressBar(int start, int end, const int &curr);

    ~ProgressBar() {
        cout << "100% done" << endl;
    }
};

And the idealized usage is

for (auto [i, pb] = pair{0, ProgressBar(0, 100, i)}; i <= 100; ++i) {
    pb.update();
    /* ... */
}

This does not work for at least two reasons:

  • ProgressBar(0, 100, i) causes a compiler error, since it depends on the loop variable i, whose type has not been deduced yet (error: use of ‘i’ before deduction of ‘auto’).
  • ProgressBar(0, 100, i) needs to be evaluated after i, but I believe the pair constructor, like all C++ functions, does not guarantee any particular order of evaluation of parameters of functions.

Any design ideas for what I should do instead?


Solution

  • Why do you need two variables to count the loop? Can you not include the state as part of the progress bar.

    Then you simply need a way of exposing the current state (either as some getter or simply check if it is done via boolean check) and a way of updating it. You could use update() as that method (or add ++ to your class).

    #include <iostream>
    
    class PB
    {
        int beg;
        int end;
        int current;
        public:
            PB(int beg, int end)
                : beg(beg)
                , end(end)
                , current(beg)
            {}
            explicit operator bool()  {return current != end;}
            PB& operator++()          {++current;return *this;}
            void update()
            {
                std::cout << current << "\n";
            }
    };
    
    int main()
    {
        for (auto pb = PB(1,100); pb; ++pb) {
            pb.update();
        }
    }