Consider the following example:
#include <cstdio>
template <int N>
int fib = fib<N - 1> + fib<N - 2>;
template <> int fib<2> = 1;
template <> int fib<1> = 1;
int main()
{
std::printf("%d %d %d", fib<4>, fib<5>, fib<6>);
}
GCC 7.x, 8.x, 9.x, and 10.x all print out the expected result of
3 5 8
.Clang 5.x, 6.x, 7.x, 8.x, 9.x, and 10.x all print out
1 3 4
as a result.
Clang's behavior is surprising.
Is there any subtle interaction between variable template instantiation, global variables, and recursion in the C++ standard that I am missing?
Or is this a long-standing Clang bug?
By the way, marking fib
as constexpr
solves the issue (on godbolt.org).
From [basic.start.dynamic]/1:
fib<4>
,fib<5>
andfib<6>
are non-local variables with static storage duration that are implicitly instantiated specializations, so their dynamic initialization is unordered.The behavior is not undefined; there must be some some unspecified ordering of initialization that produces the output seen (per [basic.start.dynamic]/3.3 the initializations are indeterminately sequenced). In fact, clang initializes in the following order (noting that a variable before dynamic initialization has the value 0 from static initialization):
This is equally as valid as gcc (and MSVC) initializating in the order
fib<3>
,fib<4>
,fib<5>
,fib<6>
.