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.