I have found two good approaches to initialise integral arrays at compile times here and here.
Unfortunately, neither can be converted to initialise a float array straightforward; I find that I am not fit enough in template metaprogramming to solve this through trial-and-error.
First let me declare a use-case:
constexpr unsigned int SineLength = 360u;
constexpr unsigned int ArrayLength = SineLength+(SineLength/4u);
constexpr double PI = 3.1415926535;
float array[ArrayLength];
void fillArray(unsigned int length)
{
for(unsigned int i = 0u; i < length; ++i)
array[i] = sin(double(i)*PI/180.*360./double(SineLength));
}
As you can see, as far as the availability of information goes, this array could be declared constexpr
.
However, for the first approach linked, the generator function f
would have to look like this:
constexpr float f(unsigned int i)
{
return sin(double(i)*PI/180.*360./double(SineLength));
}
And that means that a template argument of type float
is needed. Which is not allowed.
Now, the first idea that springs to mind would be to store the float in an int variable - nothing happens to the array indices after their calculation, so pretending that they were of another type than they are (as long as byte-length is equal) is perfectly fine.
But see:
constexpr int f(unsigned int i)
{
float output = sin(double(i)*PI/180.*360./double(SineLength));
return *(int*)&output;
}
is not a valid constexpr
, as it contains more than the return statement.
constexpr int f(unsigned int i)
{
return reinterpret_cast<int>(sin(double(i)*PI/180.*360./double(SineLength)));
}
does not work either; even though one might think that reinterpret_cast
does exactly what is needed here (namely nothing), it apparently only works on pointers.
Following the second approach, the generator function would look slightly different:
template<size_t index> struct f
{
enum : float{ value = sin(double(index)*PI/180.*360./double(SineLength)) };
};
With what is essentially the same problem: That enum cannot be of type float
and the type cannot be masked as int
.
Now, even though I have only approached the problem on the path of "pretend the float
is an int
", I do not actually like that path (aside from it not working). I would much prefer a way that actually handled the float
as float
(and would just as well handle a double
as double
), but I see no way to get around the type restriction imposed.
Sadly, there are many questions about this issue, which always refer to integral types, swamping the search for this specialised issue. Similarly, questions about masking one type as the other typically do not consider the restrictions of a constexpr
or template parameter environment.
See [1][2][3] and [4][5] etc.