Mit Random-Access-Iteratoren, und eine bestimmte Größe zur Compile-Zeit unter der Annahme, können Sie ein pack of indices, dies zu tun verwenden:
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());
Dies setzt voraus, einen Compiler der Lage, die Zwischen Kopien eliding. Ich denke, diese Annahme ist keine große Sache.
Tatsächlich kann es auch mit Eingabe-Iteratoren gemacht werden, da die Berechnung jedes Elements in einer braced-init-Liste vor der Berechnung des nächsten Elements (§8.5.4/4) sequenziert wird.
// 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++)... } };
}
Da *first++
hat keine I
drin, wir brauchen eine Dummy-I
die Expansion Pack zu provozieren. Komma-Operator zur Rettung, mit void()
, Warnungen über Mangel an Effekten zum Schweigen zu bringen, und auch überladene Kommas zu verhindern.
Gibt es einen Grund für diese Präferenz? Die Leistung wird fast genau gleich sein, da der Standardkonstruktor (normalerweise) nur die Basisstrukturen zuweist, die Sie sowieso benötigen. Es würde kein zusätzliches Zuweisen, Kopieren oder Freigeben geben. –
@DavidSchwartz: Vielleicht habe ich eine const Array-Member in meiner Klasse und so muss ich es in der Initialisierungsliste und nicht den Konstruktor Körper initialisieren? – HighCommander4
--- Können wir uns auf Random-Access-Iteratoren beschränken? Wenn das so ist, habe ich eine Lösung --- Es gibt keine Möglichkeit, die * Größe * zur Kompilierzeit zu bekommen. –