Существует ли стандартный контейнер для последовательности фиксированной длины, где эта длина определяется во время выполнения. Предпочтительно, я хотел бы передать аргумент конструктору каждого элемента последовательности и использовать этот аргумент для инициализации константного члена (или ссылки). Я также хотел бы получить элемент последовательности по заданному индексу в O (1). Мне кажется, что все мои требования не могут быть выполнены одновременно.
- Я знаю, что
std::array
имеет фиксированную длину, но эта длина должна быть известна во время компиляции. -
std::vector
имеет динамический размер и позволяет передавать аргументы конструктора с помощьюemplace
. Хотя вы можетеreserve
память, чтобы избежать фактического перераспределения, тип все еще должен быть подвижным, чтобы теоретически разрешить такое перераспределение, что, например, предотвращает использование констант. - Кроме того, есть
std::list
иstd::forward_list
, которые не требуют подвижного типа, но которые все еще имеют изменяемый размер и будут работать довольно плохо при использовании шаблонов произвольного доступа. Я также чувствую, что с такими списками могут быть значительные накладные расходы, поскольку каждый узел списка, вероятно, будет выделяться отдельно. - Как ни странно,
std::valarray
- моя лучшая ставка на данный момент, поскольку она имеет фиксированную длину и не меняет размер автоматически. Хотя есть методresize
, ваш тип не должен быть подвижным, если вы на самом деле не вызываете этот метод. Основным недостатком здесь является отсутствие пользовательских аргументов конструктора, поэтому при таком подходе инициализация константных членов невозможна.
Есть ли какая-то альтернатива, которую я пропустил? Есть ли способ настроить один из стандартных контейнеров таким образом, чтобы он удовлетворял всем моим требованиям?
Изменение: чтобы дать вам более точное представление о том, что я пытаюсь сделать, см. Этот пример:
class A {
void foo(unsigned n);
};
class B {
private:
A* const a;
const unsigned i;
public:
B(A* aa) : a(aa), i(0) { }
B(A* aa, unsigned ii) : a(aa), i(ii) { }
B(const std::pair<A*, unsigned>& args) : B(args.first, args.second) { }
B(const B&) = delete;
B(B&&) = delete;
B& operator=(const B&) = delete;
B& operator=(B&&) = delete;
};
void A::foo(unsigned n) {
// Solution using forward_list should be guaranteed to work
std::forward_list<B> bs_list;
for (unsigned i = n; i != 0; --i)
bs_list.emplace_front(std::make_pair(this, i - 1));
// Solution by Arne Mertz with single ctor argumen
const std::vector<A*> ctor_args1(n, this);
const std::vector<B> bs_vector(ctor_args1.begin(), ctor_args1.end());
// Solution by Arne Mertz using intermediate creator objects
std::vector<std::pair<A*, unsigned>> ctor_args2;
ctor_args2.reserve(n);
for (unsigned i = 0; i != n; ++i)
ctor_args2.push_back(std::make_pair(this, i));
const std::vector<B> bs_vector2(ctor_args2.begin(), ctor_args2.end());
}