Eksperymentowałem z wykorzystaniem rekurencji szablonów do generowania zagnieżdżonych struktur POD i natrafiłem na pewne zachowanie, którego się nie spodziewałem. Oto uproszczony przypadek testowy:Inicjalizowanie szablonów, rekursywnych, POD struct
#include <cstddef>
template<std::size_t size>
struct RecursiveStruct {
public:
template <std::size_t start, std::size_t length>
struct Builder {
static const Builder value;
static const size_t mid = start + length/2;
static const size_t end = start + length;
Builder<start, mid - start> left;
Builder<mid, end - mid> right;
};
template <std::size_t start>
struct Builder<start, 1> {
static const Builder value;
int data;
};
static const Builder<0, size> result;
};
template<std::size_t size>
const typename RecursiveStruct<size>::template Builder<0, size>
RecursiveStruct<size>::result = Builder<0, size>::value;
template<std::size_t size>
template<std::size_t start, std::size_t length>
const typename RecursiveStruct<size>::template Builder<start, length>
RecursiveStruct<size>::Builder<start, length>::value
= { Builder<start, mid - start>::value, Builder<mid, end - mid>::value };
template<std::size_t size>
template <std::size_t start>
const typename RecursiveStruct<size>::template Builder<start, 1>
RecursiveStruct<size>::Builder<start, 1>::value = { 5 };
////////////////////////////////////////////////////////
#include <iostream>
using std::cout;
using std::endl;
using std::size_t;
int main() {
cout << RecursiveStruct<1>::result.data << endl;
cout << RecursiveStruct<2>::result.left.data << endl;
return 0;
}
Spodziewam się ten kod do wyjścia
5
5
Rzeczywiście, że to, co jest generowany, gdy mogę skompilować z GCC 4.8.4 i 5.1.
Jednak kompilacji albo z Clang (3.5 lub 3.7) lub Visual Studio 2010 zamiast skutkuje
5
0
Czy mój kod lub moje rozumienie tego złego w jakiś sposób, czy brzęk i Visual Studio jakoś zarówno mieć błędy, które powodują takie same błędne wyniki?
Jeśli nie zrozumiem, nie sądzę, że ta uwaga miałaby tutaj zastosowanie. Rozumiem, że niezdefiniowana inicjalizacja dotyczy dynamicznej inicjalizacji. Inicjalizacja ma miejsce podczas uruchamiania programu. Jak rozumiem, powodem, dla którego podany przykład jest nieokreślony, jest to, że 'fd()' może lub nie może być wstawiony przez kompilator, zatem 'd1' może być inicjowane dynamicznie lub statycznie, dlatego' d2' jest nieokreślone. W moim przypadku wszystko jest const POD, więc wszystkie powinny być statycznie zainicjalizowane. – rkjnsn
Może to być nadal nieokreślone zachowanie, ale jeśli tak, to nie sądzę, że jest to odnośnik, który tak czyni. – rkjnsn
@rkjnsn Inicjalizacja statyczna wymaga, aby została zainicjalizowana za pomocą stałego wyrażenia - dlatego niektóre obiekty są inicjalizowane dynamicznie. – Barry