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?
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();
}
}