#include <iostream>
#include <cmath> // for std::pow

template<typename Data> struct sum{
	Data operator()(const Data & a, const Data & b ){
		return a+b;
	}
};

template<typename Data> struct multiply{
	Data operator()(const Data & a, const Data & b ){
		return a*b;
	}
};

template<typename Result> struct divide{
	Result operator()(const Result & a, const Result & b ){
		return a/b;
	}
};

template<typename Result> struct nroot{
	Result operator()(const Result & a, const Result & b ){
		return std::pow(a,1.0/b);
	}
};


template<typename Data, typename Result, typename IncrOp, typename ResOp, int InitPar=0 > class mean{
public:
	// in C++98 typedef Data data_type; typedef Result result_type;
  using data_type=Data;
  using result_type=Result;
  using incrop_type=IncrOp;
  using resop_type=ResOp;

  mean(): ncount_{}, rvalue_{static_cast<data_type>(InitPar)}, mean_{} {};

  void increment(Data d){
	  ncount_++;
	  rvalue_=increment_(rvalue_,d);
	  result_type rtemp=static_cast<result_type>(rvalue_);
	  result_type ntemp=static_cast<result_type>(ncount_);
	  mean_=result_(rtemp,ntemp);
  }

  result_type get_ave() const { return mean_;}

private:
  	IncrOp increment_;
  	ResOp result_;
    Data ncount_;
    Data rvalue_;
    Result mean_;

};

int main(){
  // Since C++11
	using data_type=int;
	using result_type=double;
	using sum_type=sum<data_type>;
	using multiply_type=multiply<data_type>;
	using divide_type=divide<result_type>;
	using nroot_type=nroot<result_type>;
	using arithmetic_type=mean<data_type,result_type,sum_type,divide_type>;
	using geometrical_type=mean<data_type,result_type,multiply_type,nroot_type,1>;

	arithmetic_type a;
	geometrical_type b;
	data_type indata{};
	std::cout <<"Enter values [Ctrl-D to finish]: " <<std::endl;
	while(std::cin>>indata){
		a.increment(indata);
		b.increment(indata);
	}
	std::cout << " Arithmetic mean: " << a.get_ave() << "\n Geometrical mean: " << b.get_ave() << std::endl;
	return 0;
}