#include <vector>
#include <iostream>
#include <iterator>
#include <array>
using namespace std;
class Generator {
protected:
vector<int> v;
public:
Generator(unsigned length): v(length) {}
template<class Outputter>
void do_calculations_with_output(Outputter& out){
// perform first part of some complex operations on v
out.output(v);
// perform second part of some complex operations on v
out.output(v);
// perform some final actions
}
};
class SimpleDumpOutputter {
private:
ostream* out;
unsigned count;
public:
SimpleDumpOutputter(ostream& os): out(&os), count() {}
template<class C>
void output(const C& c) {
*out << "Step " << ++count << " of calculation: ";
copy(c.begin(),c.end(), ostream_iterator<int>(*out, " "));
*out << endl;
}
};
class FancyOutputter {
ostream* out;
int count;
public:
FancyOutputter(ostream& os): out(&os),count() {}
template<class C>
void output(const C& c) {
// create a graph using graphviz's dot language to ease visualisation of v
*out << "Step " << ++count << " of calculation: ";
*out << "Graphviz output\n";
}
};
template<class... Outputters> class AggregateOutputter : private Outputters... {
private:
template<class First, class... Rest>
struct output_helper{
template<class C>
static void do_output(AggregateOutputter* pthis,const C& c){
static_cast<First*>(pthis)->output(c);
output_helper<Rest...>::do_output(pthis,c);
}
};
template<class First>
struct output_helper<First>{
template<class C>
static void do_output(AggregateOutputter* pthis,const C& c){
static_cast<First*>(pthis)->output(c);
}
};
public:
template<class... Out>
AggregateOutputter( Out&... out): Outputters(out)...{}
template<class C>
void output(const C& c) {
output_helper<Outputters...>::do_output(this,c);
}
// first argument is dummy, because we would use the ostreams in destinations
};
int main(){
AggregateOutputter<FancyOutputter,SimpleDumpOutputter> out(cout,cout);
Generator g(10);
g.do_calculations_with_output(out);
}