2013-12-20 3 views
6

Предположим, что у меня есть следующее определение класса:Как создать boost :: tuple с указанным количеством элементов (одного типа)?

template <unsigned int N> 
class foo 
{ 
    boost::tuples::tuple<...> bar; 
}; 

Учитывая время компиляции постоянной N, я хотел бы расширить тип bar быть кортеж, который содержит N элементы определенного типа. То есть тип foo<2>::bar будет boost::tuples::tuple<T, T>. Я предполагаю, что для этого могу использовать Boost.MPL, но я еще не понял точной последовательности. Я думаю, что я мог бы сделать:

template <typename T, int N> 
struct type_repeater 
{ 
    typedef typename boost::mpl::fold< 
     boost::mpl::range_c<T, 0, N>, 
     boost::mpl::vector<>, 
     boost::mpl::push_back<_1, T> 
    >::type type; 
}; 

Итак, например type_repeater<T, 2>::type будет эквивалентно boost::mpl::vector<T, T>. Я просто не уверен, как/если я могу взять этот список типов и ввести его в список аргументов кортежа, как я хочу. Это возможно?

+0

Вам не нужно повышать для этого, если у вас есть доступ к C++ 11. Вы согласны с версией, использующей C++ 11? – OmnipotentEntity

+0

Я открыт для рассмотрения наилучшего решения для любого случая, но в конце мне понадобится хотя бы реализация C++ 03. –

ответ

3

Хотя это вполне выполнимо с переменным числом шаблонов и std::tuple, лучшее решение для того, что вы хотите, я думаю, это просто использовать std::array. Если вам просто нужен контейнер с N экземплярами T, то подпись std::array уже template <typename T, std::size_t N> class array. Я думаю, что это точно соответствует вашей потребности.

Сказав, что, если вы действительно хотите std::tuple по какой-то причине вы можете сделать это так:

#include <tuple> 

/* Forward declaration. */ 
template <std::size_t N, typename T> 
class Tuple; 

/* Convenience type alias. */ 
template <std::size_t N, typename T> 
using TTuple = typename Tuple<N, T>::type; 

/* Base case. */ 
template <typename T> 
class Tuple<0, T> { 
    public: 

    using type = std::tuple<>; 

}; // Tuple<0> 

/* Recursive case. */ 
template <std::size_t N, typename T> 
class Tuple { 
    public: 

    /* Note the use of std::declval<> here. */ 
    using type = decltype(std::tuple_cat(std::declval<std::tuple<T>>(), 
             std::declval<TTuple<N - 1, T>>())); 

}; // Tuple<N, T> 

/* std::declval<> is necessary to support non default constructable classes. */ 
class NoDefault { 
    public: 

    NoDefault() = delete; 

}; // Foo 

/* Sample use. */ 
static_assert(std::is_same<TTuple<2, NoDefault>, 
          std::tuple<NoDefault, NoDefault>>::value, ""); 

int main() {} 

Примечание: Если у вас нет доступа к C++ 11, но есть доступ для повышения, boost::array и boost::tuples::tuple будут делать штраф вместо std::array и std::tuple.

5

Это, кажется, хороший минимальный пример использования C++ 11

#include <tuple> 
template <unsigned int N, typename T> 
struct type_repeater { 
    typedef decltype(std::tuple_cat(std::tuple<T>(), typename type_repeater<N-1, T>::type())) type; 
}; 

template <typename T> 
struct type_repeater<0, T> { 
    typedef decltype(std::tuple<>()) type; 
}; 

int main() { 
    type_repeater<3, float>::type asdf; 
    std::get<0>(asdf); 
    std::get<1>(asdf); 
    std::get<2>(asdf); 
} 
+0

Хорошо, я думаю, что с этим ответом думаю. – OmnipotentEntity

+0

Это хорошо, хотя это может быть лучше, поскольку все, что он делает, многократно конкатенатирует кортежи рекурсивно. – Rapptz

+0

Это первый способ, который пришел на ум, есть ли у вас какой-либо метод, который не использует рекурсию? – OmnipotentEntity

1

Поскольку вы явно указать способ сделать MPL :: вектор в контейнер во время выполнения, я рекомендую вам остаться Boosty и использовать as_vector Фьюжн:

Учитывая ваш первоначальный пример, в котором вы MOL :: сгиб, чтобы получить MPL :: вектор, вы бы затем использовать:

boost::fusion::result_of::as_vector< 
    mpl::vector<T, T> 
>::type; 

чтобы получить Fusion Vector, который, кажется, что вы хотите. Boost Fusion заполняет промежуток между временем компиляции и временем выполнения.

Кроме того, это pre C++ 11, что по-прежнему важно для многих (возможно, большинства?) Проектов.

Смежные вопросы