【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

判別共用体 (2)

id:n7shi:20110423で取り上げた判別共用体の変換例で、C#の継承とvirtualを使った形式は冗長ですが素朴だと思います。C++なら宣言と実装を分離できるので、評価関数だけを横断的にまとめられるのではないかと思い試してみました。

#include <memory>
#include <cstdio>

using namespace std;

struct PropLogic { virtual bool evaluate() = 0; };
struct And : PropLogic
{
    shared_ptr<PropLogic> x, y;
    And(PropLogic *x, PropLogic *y) : x(x), y(y) {}
    bool evaluate();
};
struct Not : PropLogic
{
    shared_ptr<PropLogic> x;
    Not(PropLogic *x) : x(x) {}
    bool evaluate();
};
struct True : PropLogic { bool evaluate(); };
struct False : PropLogic { bool evaluate(); };

bool And::evaluate() { return x->evaluate() && y->evaluate(); }
bool Not::evaluate() { return !x->evaluate(); }
bool True::evaluate() { return true; }
bool False::evaluate() { return false; }

int main()
{
    auto hoge = shared_ptr<PropLogic>(new And(new True, new Not(new True)));
    printf("%d\n", hoge->evaluate());
}

結構良い感じです。値型で扱えれば最高なのですが、再帰的に値型のメンバを持つことが出来ないので(型のサイズが一意に決まらないため)、仕方なくスマートポインタを使用しています。

おまけ

共用体に判別フラグを付ければ、用語的には近そうです。

struct PropLogic
{
    int type;
    union
    {
        struct { struct PropLogic *x, *y; } And;
        struct { struct PropLogic *x; } Not;
        struct {} True;
        struct {} False;
    };
};

共用体の中ではスマートポインタが使えないため、生ポインタになっています。C言語でもコンパイルが通ります。しかしunionにするメリットが特にないため、あまり意味のないコードです。F#の判別共用体そのものは共用体として捉えるよりも、継承の一種と捉える方が良さそうです。