Как создать кортеж boost::с заданным количеством элементов (одного типа)?

предположим, что у меня есть следующее определение класса:

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

учитывая константу времени компиляции N, Я хотел бы расширить типа bar быть кортежем, который держит N элементы указанного типа. То есть тип foo<2>::bar будет boost::tuples::tuple<T, T>. Я предполагаю, что я могу использовать импульс.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>. Я просто не уверен, как/если я могу взять этот список типов и ввести его в список аргументов кортежа, как я хочу. Возможно ли это?

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.


Это, кажется, хороший минимальный пример использования 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);
}

поскольку вы явно просите способ сделать mpl:: vector в контейнер времени выполнения, я рекомендую вам оставаться Boosty и использовать Fusion's as_vector:

учитывая ваш начальный пример, где вы MOL::fold, чтобы получить mpl:: vector, вы бы использовали:

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

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

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