Home > Back-end >  How to declare a compile-time constant list of different size lists in a constant header file?
How to declare a compile-time constant list of different size lists in a constant header file?

Time:08-06

Introduction

Good day,

I want to optimize my application and especially a constant header file. In order to do so, I define inline constexpr constants in order to avoid multiple copies of those variable in files they are included. And also to have compile-time constants.

I want now to add a new inline constexpr variable/arrays and this complexifies the constant header files. I want a list/array of a certain fixed size containing lists/arrays, each of them of different sizes. Finally, I would like an easy way of using it and easy accessibility.


Planned work

In the following, I note CONST to denot that the CONST values are compile-time constants. I wanted to implement my constant lists/arrays, that are later needed to be contained in a parent list/array (all defined in the constant header file), as:

inline constexpr std::array<CONST int, size1> first = { some CONST values };
inline constexpr std::array<CONST int, size2> second= { some other CONST values };
inline constexpr std::array<CONST int, size3> third = { some other CONST values };

Now, the idea is to access each array via a parent list for simplicity, if possible:

CONTAINER parent = { first, second, third };

Problems

Now I see problem arrising when I want to manipulate the arrays. Ideally, I would like the children (first, second and third) to behave as std::vector<int> and the parent as std::vector<std::vector<CONST int>*>. Because I could access first via a std::vector<CONST int>* pointer and I could change the pointed vector like the following:

// Initialization
std::vector<CONST int>* current_vec = nullptr;
...
// First assignation
current_vec = parent[0];
...
// Reassignation
current_vec = parent[1];
...

But this implementation uses vector. With std::array, I think my pointer could not do the thing because it needs to know the size of each child arrays. Also, maybe I could do something with iterators but same problem (auto keyword might be a solution?).

So, what I did for now is to use std::vector and define the child arrays as:

inline const std::vector<int> first = { some CONST values };
inline const std::vector<int> second = { some other CONST values };
inline const std::vector<int> third = { some other CONST values };

And afterwards, I define the parent as:

inline constexpr std::array<const std::vector<CONST int>*, 3> parent = {&first, &second, &third};

I can access the children like expected above:

const std::vector<CONST int>* to_access = parent[0];

It seems to work and I think the vectors are compiled-const (I guess so, if not, I wouldn't be able to compile the inline constexpr parent?).


Question

First, do you find the approach meaningful and is there something I don't see know that actually make my solution wrong? Secondly, would you use another container or another solution with constexpr rather than a const vector, an alternative that I am maybe not aware of (maybe constexpr functions or working with iterators)?

I hope everything is clear. I thank you in advance for your advises and help.

Note

I know that we can define constexpr vector since c 20 but I think it works only with the msvc c 20 compiler so I want to avoid that solution.

CodePudding user response:

The following may give you ideas:

#include <array>
const int size1 = 1;
const int size2 = 2;
const int size3 = 3;

constexpr std::array<int, size1> first = { 1 };
constexpr std::array<int, size2> second= { 2 };
constexpr std::array<int, size3> third = { 3 };

#include <variant>
// The safest, I guess, annoying to use.
constexpr std::array<
    std::variant<decltype(first), decltype(second), decltype(third)>,
    3> parent1 = {
        first, second, third
};

// The simplest - no bounds information.
constexpr std::array<const int *, 3> parent2 = {
    first.data(), second.data(), third.data()
};

// Tie bounds together with pointers.
constexpr std::array<std::pair<const int *, std::size_t>, 3> parent3 = {{
    { first.data(), first.size(), },
    { second.data(), second.size(), },
    { third.data(), third.size(), },
}};

// In C  20 we now have span
#include <span>
constexpr std::array<std::span<const int>, 3> parent4 = {{
    first, second, third
}};

// Compile-time template access.
template<int index>
constexpr auto parent5() {
    if constexpr (index == 0) {
        return first;
    } else if constexpr (index == 1) {
        return second;
    } else if constexpr (index == 2) {
        return third;
    }
}

I think accessing uniformly 3 arrays with different sizes is asking for out-of-bounds trouble. Remember to check bounds to avoid undefined behavior.

  • Related