Учитывая следующий код:
#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;
}
где статический член value структуры шаблона foo рекурсивно инициализируется, я получаю разные результаты от g++:
3 2 1 0
и от кланг++:
1 1 1 0
Итак, кажется, что g++ инициализирует foo<N>::value рекурсивно, используя инициализированное значение foo<N-1u>::value, где clang++ использует ноль для foo<N-1u>::value.
Два вопроса:





Это не указано. Оба компилятора правы.
Вот соответствующие фрагменты из cppreference "инициализация".
For all other non-local static and thread-local variables, Zero initialization takes place
Итак, для всех этих переменных они равны нулю при загрузке программы. Потом:
After all static initialization is completed, dynamic initialization of non-local variables occurs in the following situations:
1) Unordered dynamic initialization, which applies only to (static/thread-local) class template static data members and ... that aren't explicitly specialized.
И эти переменные соответствуют критериям. И затем он говорит:
Initialization of such static variables is indeterminately sequenced with respect to all other dynamic initialization ....
Это означает, что любая последовательность инициализации подходит. Оба компилятора правы.
Чтобы избежать этой проблемы, используйте constexpr вместо принудительной «постоянной инициализации».
Это Неопределенные.
Вы используете построить, где вы ссылаетесь на определение переменной на себя - возможно, это похоже на выражение int i = i-1. В случае clang это просто использование общего определения шаблона
template <std::size_t N>
struct foo
{ static std::size_t value; };//without specialization this will be ZERO initialized
потому что он не имеет видимый «сам», как обычный класс или функция шаблона (в отличие от случая gcc).
Подводить итоги:
1) Легальный
2) Не указано
Чтобы избежать проблем, используйте constexpr и вместо этого настройте шаблон класса.