NAND logic

#include <iostream>

// 真偽値を表す型。
class FBool
{
public:
    // 真偽値がvalueであるFBoolオブジェクトを生成する。
    FBool(bool Value)
    {
        this->Value = Value;
    }
private:
    // このFBoolの真偽値。
    bool Value;
    friend std::ostream& operator<<(
        std::ostream&,
        const FBool);
    // このクラスの内部の値を読めるのはNand関数だけとする。
    friend FBool Nand(
        const FBool,
        const FBool
    );
};

// FBool型オブジェクトを印字可能にする。
std::ostream& operator<<(
    std::ostream& Stream,
    const FBool Object)
{
    Stream << Object.Value;
    return Stream;    
}

// 与えられた真偽値xとyがともに真のときのみ偽である関数。
FBool Nand(
    const FBool X,
    const FBool Y)
{
    // Nand関数は所与に与えられるものとして生のブーリアン演算を用いる。
    if (X.Value && Y.Value)
    {
        return FBool(false);
    }
    else
    {
        return FBool(true);
    }
}

// 関数の型に別名をつける。
using FUnaryOperator = FBool (*)(
    const FBool);
using FBinaryOperator = FBool (*)(
    const FBool,
    const FBool);
// 単項演算子について、すべての入力パターンを出力する。
void Examine(FUnaryOperator Operator)
{
    FBool False = FBool(false);
    FBool True = FBool(true);
    std::cout << Operator(False) << ", ";
    std::cout << Operator(True) << "\n";
}
// 2項演算子について、すべての入力パターンを出力する。
void Examine(FBinaryOperator Operator)
{
    FBool False = FBool(false);
    FBool True = FBool(true);
    std::cout << Operator(False, False) << ", ";
    std::cout << Operator(False, True) << ", ";
    std::cout << Operator(True, False) << ", ";
    std::cout << Operator(True, True) << "\n";
}

FBool Not(const FBool X)
{
    // Nandの出力abcdの1110のうちbdを取れば10つまりNot演算となる。
    return Nand(X, X);
}

FBool And(
    const FBool X,
    const FBool Y)
{
    // NandはNot Andの意味だから、さらにNotすればAndになる。
    return Not(Nand(X, Y));
}

FBool Or(
    const FBool X,
    const FBool Y)
{
    // 出力がabcdである関数について入力XをNotすればcdabになる。
    // 出力がabcdである関数について入力YをNotすればbadcになる。
    // そのためXもYもNotすればdcbaになる。
    // よってNandつまり1110のXもYもNotすれば0111つまりOrとなる。
    return Nand(
        Not(X),
        Not(Y));
}

int main()
{
    Examine(Not);
    Examine(And);
    Examine(Or);
    // NotとAndとOrは使いやすいので、他の演算子も作れる。
}

// Output:
// 1, 0
// 0, 0, 0, 1
// 0, 1, 1, 1