One of the most common arrays used throughout engineering modelling is one with entries $0, 1, 2, 3, 4, ...$. In C++, it seems less obvious as to how to create such an array without an explicit for loop. More generally, one may want to store an arithmetic sequence.
These examples, together with geometric and arbitrary explicitly-defined sequences, can be seen at replit.com.
The std::iota function takes an argument and assigns that to the first entry of a range, and after each assignment, it increments the argument before going onto the next assignment.
#include <vector> #include <numeric> int main(); int main() { std::size_t const N{ 20 }; int array[N]; std::vector data( 16 ); // Fill the array with 0, 1, 2, 3, ... std::iota( array, array + N, 0 ); // Fill the std::vector with 0, 1, 2, 3, ... std::iota( data.begin(), data.end(), 0 ); return 0; }
If you want an arithmetic sequence, you can do the following:
template <typename T> class Arith; template <typename T> class Arith { public: Arith( T initial, T difference ); Arith &operator++(); Arith operator++( int ); Arith &operator+=( T n ); T operator*() const; T &operator*(); operator T() const; private: T value_; T difference_; }; template <typename T> Arith<T>::Arith( T initial, T difference ): value_{ initial }, difference_{ difference } { // Empty constructor } template <typename T> Arith<T> &Arith<T>::operator++() { value_ += difference_; return *this; } template <typename T> Arith<T> Arith<T>::operator++( int ) { Arith copy{ *this }; value_ += difference_; return copy; } template <typename T> Arith<T> &Arith<T>::operator+=( T n ) { value_ += n*difference_; return *this; } template <typename T> T Arith<T>::operator*() const { return value_; } template <typename T> T &Arith<T>::operator*() { return value_; } template <typename T> Arith<T>::operator T() const { return value_; }
You can now use this class to initialize a range of entries with an arithmetic sequence:
#include <vector> #include <numeric> int main(); int main() { std::size_t const N{ 20 }; int array[N]; std::vector<int> data( 16 ); // 3, 5, 7, 9, 11, ... std::iota( array, array + N, Arith<int>{3, 2} ); // 4, 9, 14, 19, 24, ... std::iota( data.begin(), data.end(), Arith<int>{4, 5} ); // Print the array for ( std::size_t k{ 0 }; k < N; ++k ) { std::cout << array[k] << ", "; } std::cout << "..." << std::endl; // Print the vector for ( int value : data ) { std::cout << value << ", "; } std::cout << "..." << std::endl; return 0; }
The std::generate(...) function calls the argument function successively on each entry of the range. Thus, we may instead have
template <typename T> class Arithmetic_generator; template <typename T> class Arithmetic_generator { public: Arithmetic_generator( T initial, T difference ); T operator()(); private: T value_; T difference_; }; template <typename T> Arithmetic_generator<T>::Arithmetic_generator( T initial, T difference ): value_{ initial }, difference_{ difference } { // Empty constructor } template <typename T> T Arithmetic_generator<T>::operator()() { T result{ value_ }; value_ += difference_; return result; }
This can then be used as follows:
#include <vector> #include <algorithm> int main(); int main() { std::size_t const N{ 20 }; int array[N]; std::vector<int> data( 16 ); // 3, 5, 7, 9, 11, ... std::generate( array, array + N, Arithmetic_generator<int>{3, 2} ); // 4, 9, 14, 19, 24, ... std::generate( data.begin(), data.end(), Arithmetic_generator<int>{4, 5} ); // Print the array for ( std::size_t k{ 0 }; k < N; ++k ) { std::cout << array[k] << ", "; } std::cout << "..." << std::endl; // Print the vector for ( int value : data ) { std::cout << value << ", "; } std::cout << "..." << std::endl; return 0; }