読者です 読者をやめる 読者になる 読者になる

型のプレースホルダー

C++

Boost.MPLのapplyメタ関数のように、プレースホルダーにしたテンプレート引数をあとで置き換える実装のサンプルです。

テンプレートテンプレートパラメータを使った部分特殊化で実装します。

#include <iostream>
#include <vector>
#include <list>

template <class T>
class my_vector {
    std::vector<T> data_;
public:
    void push_back(const T& x)
    { data_.push_back(x); }

    void print()
    {
        for (const T& x : data_) {
            std::cout << x << std::endl;
        }
    }
};

template <class T>
class my_list {
    std::list<T> data_;
public:
    void push_back(const T& x)
    { data_.push_back(x); }

    void print()
    {
        for (const T& x : data_) {
            std::cout << x << std::endl;
        }
    }
};

struct _ {};

template <class>
struct arg;

template <template <class> class T>
struct arg<T<_>> {
    template <class Arg>
    using apply = T<Arg>;
};

template <class Container>
class X {
    // 2. プレースホルダーになってるテンプレート引数をあとで置き換える
    typename arg<Container>::template apply<int> cont;
public:
    void push()
    { cont.push_back(3); }

    void print()
    { cont.print(); }
};

int main()
{
    X<my_vector<_>> x1; // 1. テンプレート引数をプレースホルダーにして
    x1.push();
    x1.print();

    X<my_list<_>> x2;
    x2.push();
    x2.print();
}

出力:

3
3

テンプレートテンプレートパラメータはテンプレート引数を埋めないと型になれないので扱いが難しいです。なので、テンプレートテンプレートパラメータを直接使うのではなく、プレースホルダーを使うか、Boost.Graphのadjacency_listのようにポリシー方式で渡すかにするのがよいです。