Инициализировать std :: array с диапазоном (пара итераторов)

Как я могу инициализироватьstd::array из диапазона (как определено парой итераторов)?

Что-то вроде этого:

vector<T> v;
...
// I know v has exactly N elements (e.g. I just called v.resize(N))
// Now I want a initialized with those elements
array<T, N> a(???);  // what to put here?

я думалarray будет иметь конструктор, принимающий пару итераторов, чтобы я мог сделатьarray<T, N> a(v.begin(), v.end()), но, похоже, не имеет конструкторов вообще!

я знаю что могуcopy вектор в массив, но я бы скорее инициализировал массив содержимым вектора напрямую, не создавая его по умолчанию. Как я могу?

 R. Martinho Fernandes07 июн. 2012 г., 12:22
--- Можем ли мы ограничиться итераторами с произвольным доступом? Если так, у меня есть какое-то решение --- Неважно, нет никакого способа получитьsize во время компиляции.
 HighCommander407 июн. 2012 г., 12:03
@DavidSchwartz: Возможно, в моем классе есть член массива const, и поэтому мне нужно инициализировать его в списке инициализаторов, а не в теле конструктора?
 HighCommander407 июн. 2012 г., 12:26
@ R.MartinhoFernandes: Вы можетеassume размер N во время компиляции - тот же N, который появляется в качестве параметра шаблонаarray.
 R. Martinho Fernandes07 июн. 2012 г., 13:20
На самом деле, это можно сделать с помощью итераторов ввода!
 David Schwartz07 июн. 2012 г., 11:57
Есть ли какая-то причина для этого предпочтения? Производительность будет почти точно такой же, потому что конструктор по умолчанию (обычно) в любом случае выделяет только те базовые структуры, которые вам нужны. Не было бы дополнительного выделения, копирования или освобождения.

Ответы на вопрос(3)

Как вы заметили, std :: array вообще не имеет конструкторов (кроме созданного компилятором конструктора по умолчанию).

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

Ты можешь использоватьBOOST_PP_ENUM как:

include <boost/preprocessor/repetition/enum.hpp>

#define INIT(z, i, v) v[i] 

std::vector<int> v;

//fill v with at least 5 items 

std::array<int,5> a = { BOOST_PP_ENUM(5, INIT, v) };  //MAGIC

Здесь последняя строка раскрывается как:

std::array<int,5> a = {v[0], v[1], v[2], v[3], v[4]}; //EXPANDED LINE

чего ты хочешь

Решение Вопроса

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

template <std::size_t... Indices>
struct indices {
    using next = indices<Indices..., sizeof...(Indices)>;
};
template <std::size_t N>
struct build_indices {
    using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0> {
    using type = indices<>;
};
template <std::size_t N>
using BuildIndices = typename build_indices<N>::type;

template <typename Iterator>
using ValueType = typename std::iterator_traits<Iterator>::value_type;

// internal overload with indices tag
template <std::size_t... I, typename RandomAccessIterator,
          typename Array = std::array<ValueType<RandomAccessIterator>, sizeof...(I)>>
Array make_array(RandomAccessIterator first, indices<I...>) {
    return Array { { first[I]... } };
}

// externally visible interface
template <std::size_t N, typename RandomAccessIterator>
std::array<ValueType<RandomAccessIterator>, N>
make_array(RandomAccessIterator first, RandomAccessIterator last) {
    // last is not relevant if we're assuming the size is N
    // I'll assert it is correct anyway
    assert(last - first == N); 
    return make_array(first, BuildIndices<N> {});
}

// usage
auto a = make_array<N>(v.begin(), v.end());

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

На самом деле, это может быть сделано и с входными итераторами, поскольку вычисление каждого элемента в списке с фигурными скобками инициируется до вычисления следующего элемента (& # xA7; 8.5.4 / 4).

// internal overload with indices tag
template <std::size_t... I, typename InputIterator,
          typename Array = std::array<ValueType<InputIterator>, sizeof...(I)>>
Array make_array(InputIterator first, indices<I...>) {
    return Array { { (void(I), *first++)... } };
}    

поскольку*first++ не имеет каких-либоI в нем нам нужен манекенI спровоцировать расширение пакета. Запятая оператора на помощь, сvoid() заставить замолчать предупреждения об отсутствии эффектов, а также предотвращение перегруженных запятых.

 07 июн. 2012 г., 14:33
Смотрите мое решение, которое использует Boost.
 07 июн. 2012 г., 15:49
@ecatmur да, что-то в этом роде. Я не хотел включать это здесь, потому что это не первый раз, когда я использую этот трюк в ответе. Я думаю, что вместо этого я просто сошлюсь на предыдущий ответ.
 08 июн. 2012 г., 04:32
@ HighCommander4 FWIW, Clang также поддерживает их :) Я думаю, что шаблоны псевдонимов сильно недооценены. Я начал использовать их несколько месяцев назад и уже не могу жить без них :)
 07 июн. 2012 г., 14:22
Чтобы уточнить,BuildIndices этоbuild_indices шаблон на связанной странице? Не могли бы вы включить это здесь, чтобы сделать этот ответ автономным?
 07 июн. 2012 г., 14:18
+1. Ницца. (но на этот раз я ненавижу этот синтаксис:template<typename<Xyz<template<typename<Abc...>>>>>, Я имею в виду WTF.)

Ваш ответ на вопрос