I favor the @πάντα ῥεῖ (How do you write that!?) idea.
First we have the abstract_sink
a struct that will act as interface for all ours sinks.
struct abstract_sink {
virtual void on_progress_inc(int progress) = 0;
};
Two example sinks:
struct my_sink : abstract_sink {
void on_progress_inc(int progress) {
std::cout << "The progress: " << progress << "%" << std::endl;
}
};
struct my_another_sink : abstract_sink {
void on_progress_inc(int progress) {
std::cout << "The progress: " << progress << " --- " << std::endl;
}
};
And finally a functor (See: C++ Functors - and their uses) will be implemented, this functor takes the place of your member function.
template<typename Sink>
struct process_file_functor
{
// Constructor.
process_file_functor(Sink &sink)
{
m_sink = std::make_shared<Sink>(sink);
}
void operator()(std::string infile, std::string outfile)
{
std::fstream inf(infile);
std::fstream out(outfile);
int total_lines = std::count(std::istreambuf_iterator<char>(inf), std::istreambuf_iterator<char>(), '\n');
inf.seekg(0);
int progress = 0;
for (std::string line; std::getline(inf, line); )
{
/*
Here you will do what you have to do and in every iteration
you will compute progress = 100 * lines_processed / total_lines and call...
*/
progress++;
m_sink->on_progress_inc(100 * progress/total_lines); // Here you notify the progress.
}
}
std::shared_ptr<Sink> m_sink;
};
Exmaple of use:
#include <iostream>
#include <fstream>
#include <memory>
#include <string>
#include <thread>
int main(int argc, char *argv[])
{
my_sink ms;
my_another_sink mas;
process_file_functor<my_sink> pfile(ms);
process_file_functor<my_another_sink> pfile1(mas);
std::thread t1(pfile, "data1.txt", "data2.txt");
std::thread t2(pfile1, "data1.txt", "data2.txt");
t1.join();
t2.join();
return 0;
}
IMPORTANT: This code don't deal with concurrency, don't use it for production is just ilustrative.