Skip to content

Instantly share code, notes, and snippets.

@paosidufygthrj
Last active August 29, 2015 14:27
Show Gist options
  • Save paosidufygthrj/035ee1900ec3022b081c to your computer and use it in GitHub Desktop.
Save paosidufygthrj/035ee1900ec3022b081c to your computer and use it in GitHub Desktop.
[C++]switchの置き換えを考える
// 定数により switch で振る舞いを切り替える
// パラメータが登録されていない定数の場合は assert を実行
#include <iostream>
#include <cassert>
using namespace std;
enum class color {
red,
green,
blue,
count,
};
void print(color col) {
switch (col) {
case color::red: cout << "red" << endl; break;
case color::green: cout << "green" << endl; break;
case color::blue: cout << "blue" << endl; break;
default: assert(0); break;
}
}
int main() {
print(color::red); // red
}
// switch による振る舞いの切り替えを std::map に置き換える
// color::count 以下の定数ごとの振る舞いが実装されているか assert でチェックし、実装漏れを実行時に検出する
#include <map>
#include <functional>
#include <iostream>
#include <cassert>
using namespace std;
enum class color {
red,
green,
blue,
count,
};
inline void print(color col) {
static const map<color, function<void()>> funcs = {
{color::red, []{ cout << "red" << endl; }},
{color::green, []{ cout << "green" << endl; }},
{color::blue, []{ cout << "blue" << endl; }}
};
assert(funcs.size() == static_cast<size_t>(color::count));
auto it = funcs.find(col);
if (it != funcs.end()) {
it->second();
} else {
assert(0);
}
}
int main() {
print(color::red); // red
}
// switch による振る舞いの切り替えを Boost.MPL に置き換える
// color::count 以下の定数ごとの振る舞いの実装チェックをコンパイル時に検出する
#include <boost/mpl/set.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/insert.hpp>
#include <type_traits>
#include <iostream>
using namespace std;
using namespace boost;
enum class color {
red,
green,
blue,
count,
};
// 定数ごとの振る舞いを特殊化する
template <color type>
void print();
template <>
void print<color::red>() {
cout << "red" << endl;
}
template <>
void print<color::green>() {
cout << "green" << endl;
}
template <>
void print<color::blue>() {
cout << "blue" << endl;
}
// 設定された値と同じ値の定数型の場合のみ実行される関数オブジェクト
struct color_printer {
color col;
color_printer(color col) : col(col) {}
template <typename T>
void operator ()(const T&) {
if (col == T::value) {
print<T::value>();
}
}
};
// 列挙型の定数を型として定義
template <color value>
using color_type = std::integral_constant <color, value>;
// 範囲を指定して列挙型の定数型の配列型を取得するメタ関数
template<color Begin, color End, typename Ignore = void>
struct color_range {
using type = mpl::set<>;
};
template<color Begin, color End>
struct color_range<Begin, End, typename std::enable_if<(Begin < End)>::type> {
static const auto next = static_cast<color>(static_cast<int>(Begin)+1);
using type = typename mpl::insert<typename color_range<next, End>::type, color_type<Begin>>::type;
};
void print(color col) {
using range = typename color_range<color::red, color::count>::type;
static_assert(mpl::size<range>::value == static_cast<size_t>(color::count), "message");
color_printer f(col);
mpl::for_each<range>(f);
}
int main() {
print(color::red); // red
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment