Listing a: Händisch erzeugtes Funktionsobjekt
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

bool myless(int lhs, int rhs)
{
    return lhs<rhs;
}

struct MyLess
{
    explicit MyLess(int v) : rhs(v) {}

    bool operator()(int lhs) const { return myless(lhs, rhs); }

private:
   int rhs;
};

int main()
{
    vector<int> v { 1, 2, 3, 5, 7, 11, 13 };

    auto n = count_if(begin(v), end(v), MyLess(4));
    cout << "Anzahl kleiner 4: " << n << '\n';

    n = count_if(begin(v), end(v), MyLess(8));
    cout << "Anzahl kleiner 8: " << n << '\n';
}

// Ausgabe
// Anzahl kleiner 4: 3
// Anzahl kleiner 8: 5

-----

Listing b: Quadratfunktion
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

ostream& operator<<(ostream& out, const vector<int>& v)
{
   for_each(cbegin(v), cend(v), [&out](int n){ out << n << ' '; });
   return out;
}

struct Variable
{
   int operator()(int n) const { return n; }
};

Variable x;

struct SquareOfVariable
{
   Variable var;
   explicit SquareOfVariable(Variable v) : var(v) {}
   int operator()(int n) const { n = var(n); return n*n; }
};

SquareOfVariable square(Variable v)
{
   return SquareOfVariable(v);
}

int main()
{
   vector<int> v { 1, 2, 3 };
   cout << v << '\n';

   transform(cbegin(v), cend(v), begin(v), square(x));

   cout << v << '\n';
}

// Ausgabe
// 1 2 3
// 1 4 9

-----

Listing 1: Die verschiedenen Loglevel definieren
bool doAction()
{
    Log(LogLevel::Debug, "Funktion doAction startet");
    try
    {
      Log(LogLevel::Action, "Action startet");

      DbConnection db = getDbConnection();
      Log(LogLevel::Info, "DB-Connection geholt");

      // Action-Logik Teil 1 ausfuehren ...
      Log(LogLevel::Debug, " Action Logik Teil 1");

      // Action-Logik Teil 2 ausfuehren ...
      Log(LogLevel::Debug, " Action Logik Teil 2");

      // In C++ besser automatisch
      db.close();
      Log(LogLevel::Info, "DB-Connection geschlossen");

      // In C++ besser automatisch
      Log(LogLevel::Action, "Action fertig");
    }
    catch(const std::exception& ex)
    {
      Log(LogLevel::Error, "Action fehlgeschlagen wegen: "s + ex.what());
      return false;
    }
    // In C++ besser automatisch
    Log(LogLevel::Debug, "Funktion doAction endet");
    return true;
}

-----

Listing 2: Einen STL-Algorithmus mit std::bind nutzen
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
using std::placeholders::_1;

bool myless(int n1, int n2)
{
    return n1<n2;
}

int main()
{
    vector<int> v { 1, 2, 3, 5, 7, 11, 13 };

    auto n = count_if(begin(v), end(v), bind(myless, _1, 4));
    cout << "Anzahl kleiner 4: " << n << '\n';

    n = count_if(begin(v), end(v), bind(myless, _1, 8));
    cout << "Anzahl kleiner 8: " << n << '\n';
}

// Ausgabe
// Anzahl kleiner 4: 3
// Anzahl kleiner 8: 5

-----

Listing 3: Signatur mit bind anpassen
#include <iostream>
#include <functional>
using namespace std;
using std::placeholders::_1;

bool myless(int lhs, int rhs)
{
    return lhs<rhs;
}

int main()
{
    cout << boolalpha;

    auto obj = bind(myless, _1, 4);
    cout << "2<4 => " << obj(2) << '\n';
    cout << "3<4 => " << obj(3) << '\n';
    cout << "4<4 => " << obj(4) << '\n';
    cout << "5<4 => " << obj(5) << '\n';
}

// Ausgabe
// 2<4 => true
// 3<4 => true
// 4<4 => false
// 5<4 => false

-----

Listing 4: Identitätsobjekt x mit transform angewendet
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

ostream& operator<<(ostream& out, const vector<int>& v)
{
    for_each(cbegin(v), cend(v), [&out](int n){ out << n << ' '; });
    return out;
}

// Code erstellt Element x
struct Variable
{
    int operator()(int n) const { return n; }
};

Variable x;

int main()
{
    vector<int> v { 1, 2, 3 };
    cout << v << '\n';

    transform(cbegin(v), cend(v), begin(v), x);

    cout << v << '\n';
}

// Ausgabe
// 1 2 3
// 1 2 3

-----

Listing 5: Mathematisches Objekt, das quadriert
... // Includes- und Ausgabeoperator wie in Listing 4
struct SquareVariable
{
    int operator()(int n) const { return n*n; }
};

SquareVariable x_square;

int main()
{
    vector<int> v { 1, 2, 3 };
    cout << v << '\n';

    transform(cbegin(v), cend(v), begin(v), x_square);

    cout << v << '\n';
}

// Ausgabe
// 1 2 3
// 1 4 9

-----

Listing 6: Vollständige Square-Expression-Klasse, aber noch unfertige square-Funktion
struct SquareOfVariable
{
    Variable var;
    explicit SquareOfVariable(Variable v) : var(v) {}
    int operator()(int n) const { ??? }
};

SquareOfVariable square(Variable v)
{
    ???
}

-----

Listing 7: Allgemeine Square Expression mit Anwendung
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

ostream& operator<<(ostream& out, const vector<int>& v)
{
    for_each(cbegin(v), cend(v), [&out](int n){ out << n << ' '; });
    return out;
}

struct Variable
{
    int operator()(int n) const { return n; }
};

Variable x;

template<class Expr> struct Square
{
    Expr expr;
    explicit Square(Expr e) : expr(e) {}
    int operator()(int n) const { n = expr(n); return n*n; }
};

template<class Expr> Square<Expr> square(Expr expr)
{
    return Square<Expr>(expr);
}

int main()
{
    vector<int> v { 1, 2, 3 };
    cout << "Ori:  " << v << '\n';

    transform(cbegin(v), cend(v), begin(v), square(x));

    cout << "^2 -> " << v << '\n';

    v = { 1, 2, 3 };

    transform(cbegin(v), cend(v), begin(v), square(square(x)));

    cout << "^4 -> " << v << '\n';

    v = { 1, 2, 3 };

    transform(cbegin(v), cend(v), begin(v), square(square(square(x))));

    cout << "^8 -> " << v << '\n';
}

// Ausgabe
// Ori:  1 2 3
// ^2 -> 1 4 9
// ^4 -> 1 16 81
// ^8 -> 1 256 6561

-----

Listing 8: Ausgabe der vom Compiler erzeugten langen Typnamen
#include <iostream>
#include <typeinfo>
using namespace std;

struct Variable
{
    int operator()(int n) const { return n; }
};

Variable x;

template<class Expr> struct Square
{
    Expr expr;
    explicit Square(Expr e) : expr(e) {}
    int operator()(int n) const { n = expr(n); return n*n; }
};

template<class Expr> Square<Expr> square(Expr expr)
{
    return Square<Expr>(expr);
}

int main()
{
    auto obj1 = square(x);
    cout << "obj1 = square(x)\n";
    cout << "obj1 = " << typeid(obj1).name() << '\n';
    cout << "obj1(2) -> " << obj1(2) << '\n';

    auto obj2 = square(square(x));
    cout << "obj2 = square(square(x))\n";
    cout << "obj2 = " << typeid(obj2).name() << '\n';
    cout << "obj2(2) -> " << obj2(2) << '\n';

    auto obj3 = square(square(square(x)));
    cout << "obj3 = square(square(square(x)))\n";
    cout << "obj3 = " << typeid(obj3).name() << '\n';
    cout << "obj3(2) -> " << obj3(2) << '\n';
}

// Ausgabe
// obj1 = square(x)
// obj1 = struct Square<struct Variable>
// obj1(2) -> 4
// obj2 = square(square(x))
// obj2 = struct Square<struct Square<struct Variable> >
// obj2(2) -> 16
// obj3 = square(square(square(x)))
// obj3 = struct Square<struct Square<struct Square<struct Variable> > >
// obj3(2) -> 256

-----

Listing 9: Expressions für Quadrat und negatives Vorzeichen
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

ostream& operator<<(ostream& out, const vector<int>& v)
{
    for_each(cbegin(v), cend(v), [&out](int n){ out << n << ' '; });
    return out;
}

struct Variable
{
    int operator()(int n) const { return n; }
};

Variable x;

template<class Expr> struct Square
{
    Expr expr;
    explicit Square(Expr e) : expr(e) {}
    int operator()(int n) const { n = expr(n); return n*n; }
};

template<class Expr> Square<Expr> square(Expr expr)
{
    return Square<Expr>(expr);
}

// unären Ausdruck hinzufügen
template<class Expr> struct Neg
{
    Expr expr;
    explicit Neg(Expr e) : expr(e) {}
    int operator()(int n) const { return -expr(n); }
};

template<class Expr> Neg<Expr> operator-(Expr expr)
{
    return Neg<Expr>(expr);
}

template<class Expr> void execute(const char* msg, Expr expr)
{
    vector<int> v { 1, 2, 3, 4 };

    transform(cbegin(v), cend(v), begin(v), expr);

    cout << msg << v << '\n';
}

int main()
{
    execute(" x       ->  ", x);
    execute("-x       ->  ", -x);
    execute("(-x)^2   ->  ", square(-x));
    execute("-(x^2)   ->  ", -square(x)); 
    execute("--(x^2)  ->  ", - -square(x));
}

// Ausgabe
// x        ->  1 2 3 4
// -x       ->  -1 -2 -3 -4
// (-x)^2   ->  1 4 9 16
// -(x^2)   ->  -1 -4 -9 -16
// --(x^2)  ->  1 4 9 16

-----

Listing 10: Expressions für die Addition
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

ostream& operator<<(ostream& out, const vector<int>& v)
{
    for_each(cbegin(v), cend(v), [&out](int n){ out << n << ' '; });
    return out;
}

struct Variable
{
    int operator()(int n) const { return n; }
};

Variable x;

// Funktion add hinzufügen
template<class LExpr, class RExpr> struct Add
{
    LExpr lexpr;
    RExpr rexpr;
    Add(LExpr le, RExpr re) : lexpr(le), rexpr(re) {}
    int operator()(int n) const { return lexpr(n) + rexpr(n); }
};

template<class LExpr, class RExpr> Add<LExpr, RExpr> operator+(LExpr le, RExpr re)
{
    return Add<LExpr, RExpr>(le, re);
}

template<class Expr> void execute(const char* msg, Expr expr)
{
    vector<int> v { 1, 2, 3, 4 };

    transform(cbegin(v), cend(v), begin(v), expr);

    cout << msg << v << '\n';
}

int main()
{
    execute("x        ->  ", x);
    execute("x+x      ->  ", x+x);
    execute("x+x+x    ->  ", x+x+x);
    execute("x+x+x+x  ->  ", x+x+x+x);
}

// Ausgabe
// x        ->  1 2 3 4
// x+x      ->  2 4 6 8
// x+x+x    ->  3 6 9 12
// x+x+x+x  ->  4 8 12 16

-----

Listing 11: Expression-Klasse für Konstanten
struct Constant
{
    const int value;
    explicit Constant(int n) : value(n) {}
    int operator()(int) const { return value; }
};

Constant c1(1);
Constant c2(2);
Constant c3(3);

-----

Listing 12: Interferenz des Expression-Plusoperators mit anderen Plusoperatoren
template<class LExp, class RExp> Add<LExp, RExp> operator+(LExp, RExp);

class A
{
public:
    A() {}
    A(int) {}
};
A operator+(const A&, const A&) { return A(); }

A a, a1, a2;
a = a1 + a2;       // Okay
a = 1 + a2;        // -> Compiler-Error
a = a1 + 2;        // -> Compiler-Error

-----

Listing 13: Lösung für die Interferenz der Plusoperatoren
Expr<Variable> x((Variable()));

template<class A> Expr<Square<A>> square(Expr<A> a)
{
    return Expr<Square<A>>(Square<A>(a.expr));
}

template<class El, class Er> Expr<Add<El, Er>>
    operator+(Expr<El> el, Expr<Er> er)
{
    return Expr<Add<El, Er>>(Add<El, Er>(el.expr, er.expr));
}

-----

Listing 14: Logfunktion für Expression-Argumente
enum class LogLevel { All, Nothing };

template<class Expr> void Log(LogLevel level, Expr expr)
{
    if (level == LogLevel::All)
    {
      string msg;
      expr(msg);
      cout << "Log: " << msg << '\n';
    }
}

-----

Listing 15: Expression-Logfunktion mit Werten
int val1 = 42;
double val2 = 3.14;
const char* val3 = "C-Text";
string val4("String");

Log(LogLevel::All, 11_log);
Log(LogLevel::All, 12_log + val1 + val2 + val3 + val4);

// Ausgabe
// Log: arg1=11
// Log: arg1=12, arg2=42, arg3=3.140000, arg4=C-Text, arg5=String

-----

Listing 16: Verbesserte Logausgabe durch Templatespezialisierung
#include <iostream>
#include <string>
using namespace std;

enum class LogLevel { All, Nothing };

template<class Expr> void Log(LogLevel level, Expr expr)
{
    if (level == LogLevel::All)
    {
       string msg;
       expr.operator()<true>(msg);
       cout << "Log: " << msg << '\n';
    }
}

inline const char* to_string(const char* p)
{
   return p;
}

inline const string& to_string(const string& s)
{
    return s;
}

template<class E> struct Expr
{
    E expr;
    constexpr explicit Expr(E e) : expr(e) {}
    template<bool b> constexpr void operator()(string& msg) const
    {
       expr.operator()<b>(msg);
    }
    static constexpr size_t arg_no = E::arg_no;
};

struct Literal
{
    template<bool> constexpr void operator()(const string&) const
    {
    }
    static constexpr size_t arg_no = 0;
};

Expr<Literal> literal((Literal()));

template<class LExpr, class T> struct Logger
{
    LExpr lexpr;
    const T& t;
    constexpr Logger(LExpr le, const T& t) : lexpr(le), t(t) {}
    template<bool> void operator()(string& msg) const
    {
       lexpr.operator()<false> (msg);
       msg += "arg" + to_string(arg_no) + "=";
       msg += to_string(t);
       msg += ", ";
    }
    template<> void operator()<true>(string& msg) const
    {
       lexpr.operator() < false > (msg);
       msg += "arg" + to_string(arg_no) + "=";
       msg += to_string(t);
    }
    static constexpr size_t arg_no = LExpr::arg_no + 1;
};

template<class LExpr> struct Logger<LExpr, int>
{
    LExpr lexpr;
    const int t;
    constexpr Logger(LExpr le, const int t) : lexpr(le), t(t) {}
    template<bool> void operator()(string& msg) const
    {
       lexpr.operator() < false > (msg);
       msg += "arg" + to_string(arg_no) + "=";
       msg += to_string(t);
       msg += ", ";
    }
    template<> void operator() < true > (string& msg) const
    {
       lexpr.operator() < false > (msg);
       msg += "arg" + to_string(arg_no) + "=";
       msg += to_string(t);
    }
    static constexpr size_t arg_no = LExpr::arg_no + 1;
};

template<class LExpr, class T> constexpr Expr<Logger<LExpr, T>> operator+(Expr<LExpr> expr, T&& t)
{
    return Expr<Logger<LExpr, T>>({ expr.expr, forward<T>(t) });
}

constexpr Expr<Logger<Literal, int>> operator""_log(unsigned long long x)
{
    return Expr<Logger<Literal, int>>(Logger<Literal, int>(literal.expr, static_cast<int>(x)));
}

int main()
{
    int val1 = 42;
    double val2 = 3.14;
    const char* val3 = "C-Text";
    string val4("String");

    Log(LogLevel::All, 11_log);
    Log(LogLevel::All, 12_log + val1 + val2 + val3 + val4);
    Log(LogLevel::Nothing, 13_log);
}





