#include <iostream>
#include <iomanip>
#include <functional>
#include <algorithm>

using namespace std;

using BinBoolOp = bool(bool, bool);

bool operator==(function<BinBoolOp> f, function<BinBoolOp> g) {
for (bool x: {false, true})
    for (bool y: {false, true})
      if (f(x, y) != g(x, y))
        return false;
  return true;
}

bool commutative(function<BinBoolOp> f) {
  using namespace placeholders;
  return f == bind(f, _2, _1);
}

void tabulate(ostream &stream, string fn, function<BinBoolOp> f) {
  int w = max(1, static_cast<int>(fn.size()));
  stream << setw(w) << fn;
  for (bool y: {false, true})
    stream << setw(2) << y;
  stream << endl;
  for (bool x: {false, true}) {
    stream << setw(w) << x;
    for (bool y: {false, true}) {
      stream << setw(2) << f(x, y);
    }
    stream << endl;
  }
  stream << "Kommutativ: " << commutative(f) << endl;
}

bool logical_implies(bool a, bool b) {
  return !a || b; // Äquivalent: a <= b
}

int main() {
  tabulate(cout, "&", bit_and<bool>());
  cout << endl;
  tabulate(cout, "|", bit_or<bool>());
  cout << endl;
  tabulate(cout, "^", bit_xor<bool>());
  cout << endl;
  tabulate(cout, "=>", logical_implies);
}
