方針
- できるだけenum構文自体には手を加えない
- メンバ呼び出しをできるだけ簡単にしたい
実装
namespace Foo
{
struct Hoge
{
enum class Type : char
{
Bool,
Integer,
Float,
String,
Object,
};
// メンバ関数用インタフェースを取得するための関数
friend constexpr auto _(Type t)
{
struct {
// 数値型だったらtrueを返すメンバ(?)関数
constexpr bool isNumber() const
{
return value == Type::Integer || value == Type::Float;
}
Type value;
} tmp{ t };
return tmp;
}
};
}
int main()
{
// 定数を_()で囲んで関数を呼び出すスタイル
static_assert(_(Foo::Hoge::Type::Float).isNumber());
}
できればenum型そのものにメンバ関数を付けたいがそうもいかない
だからと言ってenum風のクラスを作るのはキツイ↓
// 元のenum構文とあまりにもかけ離れた書き方
class Type
{
char value;
constexpr Type(char value):value(value){}
public:
// 必ず手動で値を振っていかなければならない
static inline Type Bool{0};
static inline Type Integer{1};
...
// enumで普通に使える演算子もいちいち用意しないといけない
// しかもconstexpr指定してても戻り値を定数展開できないっぽい
bool operator==(Type type) const { return value == type.value; }
};
なのでenum自体は何もいじらずそのままにアクセスする部分をどうシンプルにするかということに終始しました。
今回のようにenum型を専用の構造体などで包んでから関数呼び出しをするのは割とある方法だとは思います。
ただ今回はADLとfriend指定付きフリー関数定義を利用してenum型と関数の記述位置をできるだけ近づけつつ
あらゆるenum型で共通の記述をできるようにしました。(しかもシンプル)
名前空間もできるだけ汚染しないようにしたつもりですが、_()がフリー関数なのでここではFoo空間にシンボルが
生成されてしまっています。そこだけちょっとわかりにくいところなので注意ですね。
愚痴
今のc++の文法だとenumにメンバ関数が定義できないのは理解できるんですが、正直何とかしてほしいですよね。