С случайными итераторами доступа, и при условии определенного размера во время компиляции, вы можете использовать pack of indices сделать так:
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());
Это предполагает компилятор, способный eliding промежуточных копий. Я думаю, что это предположение не является большой протяженностью.
На самом деле это можно сделать и с помощью итераторов ввода, так как вычисление каждого элемента в скобках-init-list секвенировано перед вычислением следующего элемента (§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
спровоцировать расширение пакета. Comma для спасения, с void()
, чтобы отключить предупреждения об отсутствии эффектов, а также предотвратить перегруженные запятые.
Есть ли какая-то причина для этого предпочтения? Производительность будет почти точно такой же, поскольку конструктор по умолчанию (обычно) выделяет только базовые структуры, которые вам нужны. Никакого дополнительного выделения, копирования или освобождения не будет. –
@DavidSchwartz: Возможно, у меня есть член const array в моем классе, и поэтому мне нужно инициализировать его в списке инициализаторов, а не в корпусе конструктора? – HighCommander4
--- Можем ли мы ограничить себя итераторами произвольного доступа? Если это так, у меня есть какое-то решение --- Nevermind, нет способа получить * размер * во время компиляции. –