// Uppgift:   Summera 10 inmatade heltal.
// Nyckelord: funktionspekare, funktionsobjekt, lambdafunktion, typedef, std::for_each, std::vector, const-parameter, static
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef vector<int> my_container_t;


//---- Lösning med funktionspekare
int my_sum_func(int x)
{
  // En statisk variabel lagras inte på stacken. Värdet behålls mellan
  // varje anrop, och variabeln initeras inte i funktionen utan
  // "vid kompilering" eller "vid programstart" (dvs EN gång)
  static int sum = 0;
  return sum += x;
}

int sum_by_function_pointer(my_container_t const& c)
{
  // Skicka helt enkelt med namnet på funktionen!
  for_each(c.cbegin(), c.cend(), my_sum_func);
  return my_sum_func(0);
}
//----


//---- Lösning med funktionsobjekt
// En klass som lagrar en referens till summan
class my_sum_class
{
public:
  // Referensmedlemmar och konstanter måste initieras med
  // initieringslista
  my_sum_class(int& s) : sum(s) {}

  // Speciell funktion "operator()" som gör att variabler (instanser)
  // av klasstypen kan anropas som en funktion (i detta fall som tar
  // ett heltal x som parameter och returnera void)
  void operator()(int x) { sum += x; }
private:
  int& sum;
};

int sum_by_function_object(my_container_t const& c)
{
  int sum = 0;
  // Skapa ett objekt (variabel, instans) av my_sum_class som kan
  // skickas till for_each, variablen "fo" kan anropas som en
  // funktion: fo(56) och for_each kommer att anropa den så med varje
  // element som argument
  my_sum_class fo(sum);
  for_each(c.cbegin(), c.cend(), fo);
  fo(0); // så här kan man göra med funktionsobjekt (onödigt här)
  return sum;
}
//----


//---- Lösning med lambdafunktion
int sum_by_lambda_function(my_container_t const& c)
{
  int sum = 0;
  // Här fixar kompilatorn funktionsobjektet mycket mer automatiskt...
  for_each(c.cbegin(), c.cend(), [&sum](int x)->void { sum += x; });
  return sum;
}
//----

int main()
{
  my_container_t v(10);

  for (int i = 0; i < 10; ++i)
  {
    cin >> v[i];
  }

  cout << sum_by_function_pointer(v) << endl;
  cout << sum_by_function_object(v) << endl;
  cout << sum_by_lambda_function(v) << endl;

  return 0;
}