名前付きの値
例えば何かの種類を表すときの表現として、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 と比べて手間が結構掛かっちゃうのが微妙な感じだったり。