めためた.hpp

メタプログラミングをこよなく愛する人に向けた云々かんぬん

is_sameのenum版

is_same_enum

enable_ifをよく書くのだけども値同士を比較するのになんだかいまいちこれっていうのがない
POD型の値ならばboostのmplで比較ができるが、enumはなんだかいいのが見つからない。
(僕の知識不足かもしれないですが)

一応std::enable_ifはboolの値を取るので以下のような書き方もできる

#include <type_tratis>

extern void * enabler;

enum class test_enum {
    hoge,
    hogehoge,
};

template<test_enum _E , typename std::enable_if<_E == test_enum::hoge>::type *& = enabler>
void f() {};

しかしなんか汚い。
出来ればenable_ifの中に演算子を書きたくない



というわけで書いた。

コード

#include <type_traits>

template<class _T>
struct is_same_enum
{
	template<_T L, _T R>
	struct compare
		: public std::false_type
	{};

	template<_T L>
	struct compare<L,L>
		: public std::true_type
	{};
};

extern void * enabler;

enum class test_enum {
    hoge,
    hogehoge,
};


template<test_enum _E , typename std::enable_if<is_same_enum<test_enum>::compare<_E,test_enum::hoge>::value>::type *& = enabler>
void f() {};

多少冗長にはなったが、演算子もなくなったし綺麗になった気がする。

実用性?多少意味が分かりやすくなったことぐらいじゃないかな……

templateでenumと型情報の結び付け

enumから型へ

なんとなくコードを書いている最中、唐突にenumから型情報が振り分けられたら使えるかもしれない!という訳が分からない考えが降ってきたので

書きました。

コード

template<class _Enum>
struct switch_types {
	template<
		bool _Check,
		size_t _N,
		_Enum _Select,
		_Enum _First,
		_Enum ... _Modes
	>
	struct resolve_select
	{
		static size_t const value = _N - 1;
	};

	template<
		size_t _N,
		_Enum _Select,
		_Enum _First,
		_Enum ... _Modes
	>
	struct resolve_select<false, _N, _Select,_First,_Modes ...> :
		public resolve_select<_First == _Select, _N + 1, _Select, _Modes ...>{};

	template<
		size_t _N,
		class _Check,
		class ... _Remain>
	struct resolve_type : public resolve_type<_N - 1, _Remain ... > {};

	template<
		class _Check,
		class ... _Remain>
	struct resolve_type<0, _Check, _Remain ...>
	{
		typedef _Check type;
	};

	template<_Enum ... _Modes>
	struct which {
		template<_Enum _Select>
		struct select {
			template<class ... _Types>
			struct types {
				typedef typename resolve_type<resolve_select<false, 0, _Select, _Modes ..., _Select>::value, _Types ...>::type type;
			};
		};
	};

}

使い方

enum TestEnum
{
	one = 0,	// float
	two,		// int
	three,		// double
};
template<TestEnum Select>
struct TestSelect{
	typedef typename switch_types<TestEnum>::which<one,two,three>::select<Select>::template types<float,int,double>::type type;
};

出力

int main() {
	std::cout << "float : ";
	std::cout << (typeid(TestSelect<one>::type) == typeid(float)) << std::endl;

	std::cout << "int : ";
	std::cout << (typeid(TestSelect<two>::type) == typeid(int)) << std::endl;

	std::cout << "double : ";
	std::cout << (typeid(TestSelect<three>::type) == typeid(double)) << std::endl;

	return 0;
}
float : 1
int : 1
double : 1

解説っぽいもの

switch_typeにenumの型情報を与えて
whichとtypesに対応する列挙子と型情報を順番に並べます
そしてselectで選択された列挙子とwhich内で一致する列挙子のインデックスを元にtypesから型情報を引っ張り出す仕組みです。

正直かなりごり押しした気がする。

使いどころは、そこまでない