Какой идиоматический способ генерировать числа от 0 до n-1?

Какова приемлемая идиома C ++ для генерации чисел от 0 до n-1, в произвольном типе, в массиве или в векторе?

Другими словами, как бы я написал:

template <typename T> vector<T> generate_integers_upto(size_t n);

или же

template <typename T> T* generate_integers_upto(size_t n);

0

Решение

Это скорее зависит от того, что вы хотите сделать с этими числами.

если ты действительно хотите диапазон, а не контейнер, тогда boost::irange будет более чем достаточно. Ему даже не нужна [существенная] память!

Это позволяет делать такие классные вещи, как это:

#include <iostream>
#include <boost/range/irange.hpp>

using boost::irange;
using std::cout;

int main()
{
for (auto i : irange(0, 42))
cout << i << ' ';
}

// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
1

Другие решения

Идиоматическим способом было бы возвращение по значению. Вы могли бы использовать std::iota заполнить вектор для простоты, но это вторично:

#include <vector>
#include <numeric>

template<typename T>
std::vector<T> generate(std::size_t n)
{
std::vector<T> v(n);
std::iota(std::begin(v), std::end(v), T());
return v;
}
3

Просто верните значение и позвольте компилятору решить, что (RVO, move return и т. Д.) Более эффективно:

template<typename T>
std::vector<T> generate( std::size_t n , T begin = 0u )
{
std::vector<T> result( n );

std::iota( std::begin( result ) , std::end( result ) , begin );

return result;
}

Обратите внимание, что тип возвращаемого значения по умолчанию unsigned int, Конечно, вы можете изменить значение, переданное функции, чтобы изменить возвращаемое значение, или явно указать тип возвращаемого значения:

int main()
{
auto sequence = generate<float>( 100 );
}

Эта реализация основана на std::iota() алгоритм стандартной библиотеки.

2

Если вы хотите, чтобы функция создала для вас массив, верните std::vector по значению.

Возврат ссылки, как это делает ваш первый пример, либо недопустим (если вектор был локальной переменной, которая теперь была уничтожена), либо странен и подвержен ошибкам (поскольку теперь есть вектор, который нужно каким-то образом управлять).

Возврат указателя, предположительно для выделенного массива, подвержен ошибкам, так как нет ничего, чтобы гарантировать, что вызывающая сторона освобождает его правильно.

Более гибкая альтернатива — взять диапазон итераторов. Возможно, имеет смысл перегрузить его для пары итераторов:

std::vector<int> v(10);       // non-empty vector
generate(v.begin(), v.end()); // replace existing elements

и итератор и размер:

std::vector<int> v;             // empty vector
generate(back_inserter(v), 10); // insert new elements

Обратите внимание, что библиотека C ++ 11 имеет std::iota которая действует как первая версия (и может использоваться для реализации любой из них), но не похожа на вторую.

0
По вопросам рекламы [email protected]