Гетерогенный контейнер шаблона Variadic

Мне нужно реализовать некоторый вариативный класс-контейнер шаблона с разнородными элементами, который позволяет выполнять итерацию по этим элементам. Моя первая идея - создать класс с членом std::tuple с вариативными аргументами, но получение элементов из кортежа в виде массива (через циклы) невозможно:

struct A {void prnt(){std::cout<<"A\n";} };    
struct B {void prnt(){std::cout<<"B\n";} };    
struct C {void prnt(){std::cout<<"C\n";} };

template<typename...Arg>
struct Prc
{
    Prc() : NumElems(sizeof...(Arg)), mems(std::make_tuple(Arg()...)){}

    int NumElems;
    std::tuple<Arg...> mems;

    void process()
    {
        for(int i=0; i<NumElems; ++i)
         std::get<i>(mems).prnt();//It's forbidden: "i" must be a constant
    }
};

int main()
{
    Prc<A,B,C> obj;
    obj.process();
}

Есть идеи?

P.S. Я не хочу использовать гетерогенные контейнеры boost, такие как boost::variant или boost::any.


person gorill    schedule 28.07.2013    source источник
comment
Индексы.   -  person Xeo    schedule 29.07.2013
comment
Я не уверен, что вы имеете в виду под массивностью.   -  person jsp    schedule 29.07.2013


Ответы (2)


Вот это делается с помощью индексов:

namespace detail
{
    template <int... Is>
    struct index { };

    template <int N, int... Is>
    struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };

    template <int... Is>
    struct gen_seq<0, Is...> : index<Is...> { };
}

template <typename...Args>
struct Prc
{
    std::tuple<Args...> mems;

    template <int... Is>
    void process(detail::index<Is...>)
    {
         auto l = { (std::get<Is>(mems).prnt(), 0) ... };
    }

    void process()
    {
        process(detail::gen_seq<sizeof...(Args)>());
    }
};
person 0x499602D2    schedule 28.07.2013
comment
Почему я не могу заменить детали пространства имен? В данном случае это не компилируется. - person gorill; 29.07.2013
comment
@gorill Извините, я сделал несколько ошибок в исходном коде. Я обновил свой ответ, пожалуйста, посмотрите. - person 0x499602D2; 29.07.2013
comment
Ничего страшного))) Я их нашел))) - person gorill; 29.07.2013

Вот некоторый код, который выполняет итерацию кортежа:

struct A { void print () { clog << "A" << endl; } };
struct B { void print () { clog << "B" << endl; } };
struct C { void print () { clog << "C" << endl; } };

template<unsigned N>
struct iter
{
    template<typename T>
    static void f (T &t)
    {
        iter<N-1>::f (t);
        get<N> (t).print ();
    }
};

template<>
struct iter<0>
{
    template<typename T>
    static void f (T &t)
    {
        get<0> (t).print ();
    }
};

И код вызова:

    tuple <A,B,C> t;
    iter<tuple_size<decltype(t)>::value-1>::f (t);

Я думаю, вы могли бы изменить это, чтобы соответствовать вашим потребностям. NumElements в вашем коде известен во время компиляции, поэтому я думаю, что вы бы вообще удалили этот элемент.

person jsp    schedule 28.07.2013