Suppose I have a class X
, which functionality requires a lot of constant table values, say an array A[1024]
. I have a recurrent function f
that computes its values, smth like
A[x] = f(A[x - 1]);
Suppose that A[0]
is a known constant, therefore the rest of the array is constant too. What is the best way to calculate these values beforehand, using features of modern C++, and without storaging file with hardcoded values of this array? My workaround was a const static dummy variable:
const bool X::dummy = X::SetupTables();
bool X::SetupTables() {
A[0] = 1;
for (size_t i = 1; i <= A.size(); ++i)
A[i] = f(A[i - 1]);
}
But I believe, it’s not the most beautiful way to go. Note: I emphasize that array is rather big and I want to avoid monstrosity of the code.
I think this way is more readable:
I need to make a disclaimer, that for big array sizes it is not guaranteed to generate array in constant time. And the accepted answer is more likely to generate the full array during template expansion.
But the way I propose has number of advantages:
In a particular example when you need only one value, the variant with templates generated for me only a single number, while the variant with
std::array
generated a loop.Update
Thanks to Navin I found a way to force compile time evaluation of the array.
So with slight modification the code looks as follows:
To have this compiled one needs C++17 support, otherwise operator [] from std::array is not constexpr. I also update the measurements.
On assembly output
As I mentioned earlier the template variant is more concise. Please look here for more detail.
In the template variant, when I just pick the last value of the array, the whole assembly looks as follows:
While for std::array variant I have a loop:
With std::array and return by value the assemble is identical to version with templates:
On compilation speed
I compared these two variants:
test2.cpp:
test.cpp:
The results are:
How I generated:
And if you enable optimizations, the speed of code with template is even worse:
How I generated:
My gcc version:
One example:
Requires
-ftemplate-depth=1026
g++
command line switch.Example how to make it a static member:
Since C++14,
for
loops are allowed inconstexpr
functions. Moreover, since C++17,std::array::operator[]
isconstexpr
too.So you can write something like this:
Example: https://godbolt.org/g/irrfr2
just for fun, a c++17 compact one-liner might be ( requires an std::array A, or some other memory-contiguous tuple-like ):
note that this can be used in a constexpr function too.
That said, from c++14 we can use loops in constexpr functions, so we can write a constexpr function returning an std::array directly, written (almost) the usual way.