Кортеж произвольного, но известного во время компиляции количества типов

Скажем, у меня есть тип, который параметризован другим интегральным типом POD:

template< size_t N >
struct MyFoo { /* ... */ };

С ним можно иметь кортеж из них:

typedef std::tuple< MyFoo< 1 >, MyFoo< 2 >, MyFoo< 3 > > Foo3;

Но теперь я хочу иметь тип «Foo< N >», где N — это constexpr. Один из способов добиться чего-то похожего на Foo< N >:

template< size_t N >
struct Foos;

template<> struct Foos< 1 >{ typedef std::tuple< MyFoo< 1 > > type; };
template<> struct Foos< 2 >{ typedef std::tuple< MyFoo< 1 >, MyFoo< 2 > > type; };
/* continue with this.... */

э.э. настройте его вручную для каждого N, который я хочу. Есть ли более общий способ сделать это?

Спасибо :)


person Sh4pe    schedule 25.09.2013    source источник


Ответы (2)


template<std::size_t N, std::size_t... Is>
struct MakeFoos : MakeFoos<N - 1, N, Is...>
{
};

template<std::size_t... Is>
struct MakeFoos<0, Is...>
{
    using type = std::tuple<MyFoo<Is>...>;
};

template<std::size_t N>
struct Foos
{
    using type = typename MakeFoos<N>::type;
};

Чтобы получить свой кортеж, напишите Foos<3>::type.

person Simple    schedule 25.09.2013
comment
Хороший! И есть ли способ сделать это без вариативных шаблонов? Я как-то застрял на старом стандарте... - person Sh4pe; 25.09.2013
comment
@Sh4pe, у Boost есть некоторая поддержка в этой области. - person chris; 25.09.2013
comment
@ Sh4pe Sh4pe, если вы не можете использовать C ++ 11, вам нужно сделать это так, как вы уже это делали, или использовать макросы препроцессора. - person Simple; 25.09.2013
comment
@ Sh4pe, подождите, если вы используете старый стандарт, как вы используете std::tuple? - person chris; 25.09.2013

Вам понадобится некоторый механизм для построения последовательности целых чисел от 1 до N. Остальное довольно просто:

#include <cstddef>
#include <tuple>

// to generate a sequence of indices:

template<size_t... Ns>
struct indices {
    typedef indices< Ns..., sizeof...( Ns ) > next;
};

template<size_t N>
struct make_indices {
    typedef typename make_indices< N - 1 >::type::next type;
};

template<>
struct make_indices< 0 > {
    typedef indices<> type;
};

// create a sequence and expand it inside a typedef

template<size_t N>
struct MyFoo {};

template< size_t N >
struct Foos {

    template<typename>
    struct Helper;

    template<size_t... Ns>
    struct Helper<indices<Ns...>> {
        typedef std::tuple< MyFoo<Ns>... > type;
    };

    typedef typename
    Helper< typename make_indices<N>::type >::type type;
};

Текущая демонстрация

person jrok    schedule 25.09.2013
comment
С++ 14 имеет этот механизм, кстати. - person Sebastian Redl; 25.09.2013
comment
Хороший! И есть ли способ сделать это без вариативных шаблонов? Я как-то застрял на старом стандарте... - person Sh4pe; 25.09.2013
comment
@ Sh4pe Sh4pe Это было бы так, как ты это сделал сам. Такие библиотеки, как boost, могут скрыть от вас информацию о специализациях, используя приемы препроцессора. Вы также можете посмотреть библиотеку Loki TypeList, чтобы увидеть, как все реализовано. - person jrok; 25.09.2013
comment
Обратите внимание, что мой код строит последовательность от 0 до N-1. Поиграйте немного, чтобы сделать 1..N. - person jrok; 25.09.2013
comment
@SebastianRedl, что ты имеешь в виду? - person soandos; 25.09.2013
comment
@soandos Он имеет в виду это. - person jrok; 25.09.2013