I am trying to play with template metaprogramming, constexpr and if constexpr and have come up with 3 different ways of doing a N-recursive / N-factorial operation.
All three examples are some I've found here on SO or by searching on the net - and then modified it, so they do the same
The first example is using template metaprogramming: example 1
template<int N>
struct NGenerator
{
static const int result = N + NGenerator<N-1>::result;
};
template<>
struct NGenerator<0>
{
static const int result = 1;
};
static int example1 = NGenerator<5>::result;
The second one is still using a template, but I've thrown a constexpr in: example 2
template<int N>
constexpr int example2()
{
return N + example2<N - 1>();
}
template<>
constexpr int example2<0>()
{
return 1;
}
static int ex2 = example2<5>();
The third one, is where I've removed the template and "only" use constexpr: example 3
constexpr int generator(int n)
{
return (n <= 1) ? 1 : n + generator(n - 1);
}
static int ex3 = generator(5);
In my opinion all three do the same - when the input number is a compile time constant. All three are recursive, all three work compile-time.
My question is - what is the difference between the three? Which one is most preferable?
And lastly - I would like to implement the "if constexpr" but haven't been able to, so my workaround has been to do the "if-statement" in example 3 - which isn't really a true if-statement, but the closest I could get to a compile-time if - if it is in any way the same, which I am not sure of.
With toy examples like this there won't be much of a difference. With more complex examples, recursive template instantiation practically has memory costs proportional to the sum of the lengths of all of the template-instantiated names, including arguments. This is really easy to blow up.
In my experience constexpr
functions tend to compile faster.
All 3 will be likely memoized by the compiler; but the constexpr
non-template function will spew way fewer symbols (noise).
Better than all of these would be a constexpr
function with a loop.
Compilers are free to do most of the options at runtime as you did not insist on compile time evaluation. Replace static int
with constexpr int
.