LoginSignup
4
3

More than 3 years have passed since last update.

【C++】クラステンプレートでパラメータパックを複数もらう

Posted at

こんな状況に出くわした

複雑なテンプレートを書いているとこんな状況に出くわす

// 2つ以上のパラメータパックが欲しい!
template<typename... Components, typename... Events>
class ComponentManager
{
    // ・・・
};

でもこれは当然コンパイルエラーになる
なぜならパラメータパックは最後の引数にしか使えないからだ

// できたとしても区切りがつかなくなる
ComponentManager<Component1, Component2, Event1, Event2> comp;

そこでタプルstd::tupleさんに活躍してもらうことにしましょう。1

std::tupleを使ってパラメータパックをまとめる

std::tupleを使うとこのようにまとめることができます。

// templateの中にタプル
using Components = ComponentManager<
    std::tuple<
        Component1,
        Component2
    >,
    std::tuple<
        Event1,
        Event2
    >
>;

それでは実装してみましょう。

少し不思議な書き方ですがとてもシンプルです。

template<typename Components, typename Events>
class ComponentManager;

template<typename... Components, typename... Events>
class ComponentManager<std::tuple<Components...>, std::tuple<Events...>>
{
    // ・・・
}

ぜひ、試してみてください。

応用

これを応用すればパラメータパックの2重ループが作れます

// 出力
template<typename Event, typename Component>
void PrintEventComponent()
{
    std::cout << "Event:" << typeid(Event).name() << ", "
        << "Component: " << typeid(Component).name() << std::endl;
}

template<typename Components, typename Events>
class ComponentManager;

template<typename... Components, typename... Events>
class ComponentManager<std::tuple<Components...>, std::tuple<Events...>>
{
private:
    // 内側のループ (Components)
    template<typename Event>
    static void InitializeEvent()
    {
        using accumulator_type = int[];
        accumulator_type accumulator = { 0, (PrintEventComponent<Event, Components>(), 0)... };
        (void)accumulator;
    }

public:
    // 外側のループ (Events)
    static void InitializeEvents()
    {
        using accumulator_type = int[];
        accumulator_type accumulator = { 0, (InitializeEvent<Events>(), 0)... };
        (void)accumulator;
    }
};
struct Component1 {};
struct Component2 {};
struct Event1 {};
struct Event2 {};

int main()
{
    // usingを使えば何度も使うことができる
    using Components = ComponentManager<std::tuple<Component1, Component2>, std::tuple<Event1, Event2>>;
    Components::InitializeEvents();

    return 0;
}
Event: struct Event1, Component: struct Component1
Event: struct Event1, Component: struct Component2
Event: struct Event2, Component: struct Component1
Event: struct Event2, Component: struct Component2

  1. パラメータパックがまとめられるクラスなら何でもいいです。 

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3