Given the following code:
#include <iostream>
template <std::size_t N>
struct foo
{ static std::size_t value; };
template <>
std::size_t foo<0>::value = 0u;
template <size_t N>
std::size_t foo<N>::value = 1u + foo<N - 1u>::value;
int main()
{
std::cout
<< foo<3u>::value << ' '
<< foo<2u>::value << ' '
<< foo<1u>::value << ' '
<< foo<0u>::value << std::endl;
}
where the static member value
of the template struct foo
is recursively initialized, I get different outputs from g++:
3 2 1 0
and from clang++:
1 1 1 0
So seem that g++ initializes foo<N>::value
recursively using the initialized value of foo<N-1u>::value
where clang++ uses zero for foo<N-1u>::value
.
Two questions:
- is the preceding code legit or is it Undefined Behavior in some way?
- if the preceding code is legit, who's right: g++ or clang++?
It is Unspecified.
You are using a construct where you reference a variable definition onto itself - perhaps somewhat analogue to saying
int i = i-1
. In clang case, it is just using the generic template definitionbecause it hasn't seen 'itself' like normal template class or function would (as opposed to gcc case).
To sum up:
1) Legit
2) Unspecified
To avoid issues use constexpr and specialize the class template instead.
It is unspecified. Both compilers are right.
Here are the relevant pieces from cppreference "initialization".
Static initialization
So for all these variables, they are zero when the program loads. Then:
Dynamic initialization
And these variables match the criteria. And then it says:
Which means that any sequence of initialization is fine. Both compilers are correct.
To avoid the issue use
constexpr
to force a "constant initialization" instead.