名前付きの値

例えば何かの種類を表すときの表現として、int だと何を意味しているのか分からないので

typedef int hoge_t;

とか書いたりすることはあると思うんだけど、これだと

void foo(int v);

hoge_t h;
foo(h); // OK

とかできてしまうのがなんか微妙なので、こんなのを作ってみた。

template<class Name, class T>
struct named_value
{
private:
    T v_;

public:
    named_value() : v_() { }
    named_value(const named_value& v) : v_(v.v_) { }
    named_value(const T& v) : v_(v) { }
    named_value& operator=(const named_value& v) { v_ = v.v_; return *this; }
    named_value& operator=(const T& v) { v_ = v; return *this; }
    T get() const { return v_; }
};

template<class Name, class T>
bool operator==(const named_value<Name, T>& a, const named_value<Name, T>& b) { return a.get() == b.get(); }
template<class Name, class T>
bool operator!=(const named_value<Name, T>& a, const named_value<Name, T>& b) { !(a.get() == b.get()); }

template<class Name, class T>
bool operator<(const named_value<Name, T>& a, const named_value<Name, T>& b) { return a.get() < b.get(); }
template<class Name, class T>
bool operator>(const named_value<Name, T>& a, const named_value<Name, T>& b) { return b.get() < a.get(); }
template<class Name, class T>
bool operator<=(const named_value<Name, T>& a, const named_value<Name, T>& b) { !(b.get() < a.get()); }
template<class Name, class T>
bool operator>=(const named_value<Name, T>& a, const named_value<Name, T>& b) { !(a.get() < b.get()); }

template<class Name, class T>
bool operator==(const named_value<Name, T>& a, T b) { return a.get() == b; }
template<class Name, class T>
bool operator!=(const named_value<Name, T>& a, T b) { !(a.get() == b); }

template<class Name, class T>
bool operator<(const named_value<Name, T>& a, T b) { return a.get() < b; }
template<class Name, class T>
bool operator>(const named_value<Name, T>& a, T b) { return b < a.get(); }
template<class Name, class T>
bool operator<=(const named_value<Name, T>& a, T b) { !(b < a.get()); }
template<class Name, class T>
bool operator>=(const named_value<Name, T>& a, T b) { !(a.get() < b); }

template<class Name, class T>
bool operator==(T a, const named_value<Name, T>& b) { return a == b.get(); }
template<class Name, class T>
bool operator!=(T a, const named_value<Name, T>& b) { !(a == b.get()); }

template<class Name, class T>
bool operator<(T a, const named_value<Name, T>& b) { return a < b.get(); }
template<class Name, class T>
bool operator>(T a, const named_value<Name, T>& b) { return b.get() < a; }
template<class Name, class T>
bool operator<=(T a, const named_value<Name, T>& b) { !(b.get() < a); }
template<class Name, class T>
bool operator>=(T a, const named_value<Name, T>& b) { !(a < b.get()); }

適当な型に名前を付けてしまおうという考え。
これを使うと、

struct hoge_name { };
typedef named_value<hoge_name, int> hoge_t;

void foo(int v);

hoge_t h;
foo(h); // エラー

ちゃんとエラーになってくれるのでうれしい・・・かも?


あと表現する型は int じゃなくてもいいので、

struct hoge_name
{
    struct enum_name { };
    typedef named_value<enum_name, int> enum_t;
    static const enum_t value1;
    static const enum_t value2;
};
typedef named_value<hoge_name, hoge_name::enum_t> hoge_t;

hoge_t h(hoge_name::value1);
if (h == 0) { } // エラー
if (h == hoge_name::value1) { } // OK

こんな感じに書けば int と比較できない列挙子として使えてうれしい・・・かも?
ただこの場合は value1 と value2 の初期化をどこかに書かないといけないのが面倒なので

    static enum_t value1() { return 0; }
    static enum_t value2() { return 1; }

とか書いたりするんだけど、やっぱり enum と比べて手間が結構掛かっちゃうのが微妙な感じだったり。