I have a static inline
member of a class – an std::vector
. I need to fill it with numbers – 0 through to std::numeric_limits<uint16_t>::max() - 1
.
I know there is list-initialization for containers, but I don’t feel like coming up with a macro/struct that will expand to 1,2,3, all the way to 65534.
I want to know if there is a way to cleanly initialize the container with such a sequence of numbers, considering it’s a static inline
variable.
The container needs to be static
, but if there is a way to do what I want that requires it to not be inline
, then so be it.
One way is to write a function that will fill the container and then use #pragma startup myfunc
or [[gnu::constructor]]
, but neither the macro nor the attribute are in the actual standard. And I don’t want to have functions like init_mylibrary()
akin to glfwInit()
that the user has to call in main()
before using mylibrary
.
An approach that will possibly work is to declare the container’s size through the constructor and supply a custom allocator that will initialize the memory with consecutive integers, but writing an entire allocator for this task seems like overkill. There has to be a way to do this cleanly, like how Ruby allows one to write Array.new(4) { |i| i + 10 } #=> [10, 11, 12, 13]
>Solution :
You can do this with std::generate_n
, std::iota
, but during vector construction.
RangeV3 can do a similar thing though:
#include <range/v3/all.hpp>
using ranges::views::iota;
struct X {
std::vector<int> v;
X(int n) : v(ranges::to_vector(iota(0, n))) {}
};
#include <fmt/ranges.h>
int main()
{
X x(42);
fmt::print("{}\n", x.v);
}
Prints
{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}