C++ initialize an STL container using logic, not hand-writing data

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:

Compiler Explorer

#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}

Leave a Reply