myoukakuのブログ

C++でゲームエンジンを作っていきます。

static_mapのヘルパー関数、make_static_mapを書いた(2)

static_mapのヘルパー関数、make_static_mapを書いた(1) - myoukakuのブログ の続き

static const auto m = make_static_map(
    Color::Red,    std::string("Red"),
    Color::Green,  std::string("Green"),
    Color::Blue,   std::string("Blue"));

と書けるmake_static_map関数を実現する方法を考えます。

方針としては、与えられた引数をtupleにし、そのtupleの偶数番目と奇数番目をpairにしてそれをstatic_mapに渡すようにします。 コードのイメージとしてはこんな感じです。

template <typename ... Types>
/* 戻り値の型は省略 */ make_static_map(Types...args)
{
    const auto t = std::make_tuple(args...);

    return
    {
        std::make_pair(std::get<0>(t), std::get<1>(t)),
        std::make_pair(std::get<2>(t), std::get<3>(t)),
        std::make_pair(std::get<4>(t), std::get<5>(t)),
                            .
                            .
                            .
    };
}

このためには偶数のリスト(0, 2, 4, ...)と奇数のリスト(1, 3, 5, ...)が必要です。 それにはindex_tuple技法を使います。

参考

コンパイル時に配列を結合する - iorateの日記

要点だけを抜き出したコードがこちら

template <
    typename TupleType,
    std::size_t ... EvenIndexes,
    std::size_t ... OddIndexes,
>
/* 省略 */ make_static_map_aux(
    TupleType t,
    index_tuple<EvenIndexes...>,
    index_tuple<OddIndexes...>)
{
    return
    {
        std::make_pair(
            std::get<EvenIndexes>(t),
            std::get<OddIndexes>(t)
        )...
    };
}

template <
    typename ... Types,
    std::size_t N = sizeof...(Types)
>
/* 省略 */ make_static_map(Types...args)
{
    return make_static_map_aux(
        std::make_tuple(args...),
        index_range<0, N, 2>::type(),
        index_range<1, N, 2>::type());
}

index_range<0, N, 2>::type()で偶数のリストを、index_range<1, N, 2>::type()で奇数のリストを作って渡します。 make_static_map_aux内でのパラメータパックの展開の仕方がミソです。

これで望み通りの記述が可能になりました。メデタシメデタシ。

…とはいかず、引数が多くなるとmake_tupleの部分でInternal Compiler Error(fatal error C1060: ヒープの領域を使い果たしました。)になってしまいました*1。私の環境では引数の数が80を超えたあたりでエラーになりました。

これでは使い物になりません。

続く。