7

I have a c-style array whose size is defined by a #define and can change based on compiling options, e.g.

#if LINUX
# define SIZE 4
#else
# define SIZE 5
#endif
static int myArr[SIZE] = { /* ??? */ };

How can I initialize the whole array to a non-zero value, for example all 42?

Baruch
  • 20,590
  • 28
  • 126
  • 201
  • @SamerTufail: memset is runtime, OP searches for compile time I be leave! – Klaus May 30 '19 at 09:50
  • Is `#define V 42` `#define INIT4 V, V, V, V` `#define INIT6 INIT4 , V, V` and then placing `#define INIT ` in those `#ifelses` too dumb? With `static int myArr[] = { INIT};` It's not so pretty, but it get's the job done. – Quimby May 30 '19 at 10:02
  • 6
    Is switching to a `std::array` an option? – StoryTeller - Unslander Monica May 30 '19 at 10:08
  • And how about using a library like [Boost.PP](https://www.boost.org/doc/libs/1_70_0/libs/preprocessor/doc/index.html)? – StoryTeller - Unslander Monica May 30 '19 at 10:11
  • 1
    I thought I had a sense of deja vu https://stackoverflow.com/questions/54286610/initialize-an-array-of-compile-time-constant-size-with-incrementing-numbers – StoryTeller - Unslander Monica May 30 '19 at 10:22
  • @StoryTeller I had completely forgotten that I had asked this already! . Although they are not completely the same question (there I needed consecutive numbers, here I need the same number), the answer from there can probably be adapted – Baruch May 30 '19 at 13:36

3 Answers3

8

I don't know a solution for C-style arrays, though with constexpr and C++17 you could do this with std::array.

constexpr std::array<int, SIZE> createFilledArray (int value){
   std::array<int, SIZE> a{0};
   for (auto i = 0; i < SIZE; ++i)
       a[i] = value;
   return a;
}

static constexpr auto myArr = createFilledArray(42);

Code at compiler explorer

The disadvantage of this is that you can't change the array. If you remove the constexpr from the variable, your compiler should be able to optimize this.

From C++20 on, you can force the initialization:

static constinit auto myArr = createFilledArray(42);

Not sure if the proposal is already merged in: see constinit proposal

JVApen
  • 11,008
  • 5
  • 31
  • 67
3

If you insist on builtin arrays, you can use static variables in functions:

template <std::size_t N, std::size_t... Is>
auto arr_helper2(std::index_sequence<Is...>) -> int (&)[N]
{
    static int arr[N] = {((void)Is, 42)...};
    return arr;
}

template <std::size_t N>
auto arr_helper() -> int (&)[N]
{
    return arr_helper2<N>(std::make_index_sequence<N>{});
}

static int (&arr)[SIZE] = arr_helper<SIZE>();

For example:

int main()
{
    for (std::size_t i = 0; i < SIZE; ++i)
        std::cout << arr[i] << " ";
}

live demo

JVApen
  • 11,008
  • 5
  • 31
  • 67
L. F.
  • 19,445
  • 8
  • 48
  • 82
0

For the poor souls who are still limited to C++14, here's a C++14 solution that allows you to fill the C array according to a function fill:

#include <iostream>

constexpr int SIZE = 5;
constexpr int fill(std::size_t index){ return 42; }

template <int INDEX = 0, int... Values>
struct Helper : Helper<INDEX + 1, Values..., fill(INDEX)> {};

template <int... Values>
struct Helper<SIZE, Values...>{
    static constexpr int table[SIZE] = { Values... };
};

template <int... Values>
constexpr int Helper<SIZE, Values...>::table[SIZE];

int main() {
    auto constexpr arr = Helper<0>::table;
    for(int i = 0; i < SIZE; ++i){
        std::cout << arr[i] << '\n';
    }
}

However, note that this only works for integral types.

joni
  • 6,840
  • 2
  • 13
  • 20