ho scritto un modello di classe sulla base di due tipi che viene assegnato un indice univoco sulla base di propri parametri di modello:Risultato inaspettato per un contatore di tipo utilizzando i modelli con i tipi di locali di funzioni in Clang
template<typename SK,typename T>
struct Component {
static uint const index;
};
L'aspettativa è che per ogni nuovo tipo, index
viene incrementato:
Component<X,A>::index; // 0
Component<X,B>::index; // 1
Component<Y,A>::index; // 0
Component<Y,B>::index; // 1
// ...etc
Il codice completo che assegna gli indici è il seguente:
using uint = unsigned int;
template<typename SK,typename T>
struct Component
{
static uint const index;
};
template<typename SK>
class ComponentCount
{
template<typename CSK,typename CT>
friend struct Component;
private:
template<typename T>
static uint next() {
return ComponentCount<SK>::get_counter();
}
static uint get_counter()
{
static uint counter = 0;
return counter++;
}
};
questo funziona come previsto in GCC (5.1) e MSVC con il seguente test:
// global scope
struct X {};
struct Y {};
int main()
{
// function scope
struct Z{};
uint x0 = Component<X,int>::index;
uint x1 = Component<X,double>::index;
uint x2 = Component<X,double>::index;
uint x3 = Component<X,std::string>::index;
uint x4 = Component<X,int>::index;
uint x5 = Component<X,int>::index;
std::cout << x0 << ", " << x1 << ", " << x2 << ", "
<< x3 << ", " << x4 << ", " << x5 << std::endl;
uint y0 = Component<Y,int>::index;
uint y1 = Component<Y,double>::index;
uint y2 = Component<Y,double>::index;
uint y3 = Component<Y,std::string>::index;
uint y4 = Component<Y,int>::index;
uint y5 = Component<Y,int>::index;
std::cout << y0 << ", " << y1 << ", " << y2 << ", "
<< y3 << ", " << y4 << ", " << y5 << std::endl;
uint z0 = Component<Z,int>::index;
uint z1 = Component<Z,double>::index;
uint z2 = Component<Z,double>::index;
uint z3 = Component<Z,std::string>::index;
uint z4 = Component<Z,int>::index;
uint z5 = Component<Z,int>::index;
std::cout << z0 << ", " << z1 << ", " << z2 << ", "
<< z3 << ", " << z4 << ", " << z5 << std::endl;
return 0;
}
L'uscita è
0, 1, 1, 2, 0, 0
0, 1, 1, 2, 0, 0
0, 1, 1, 2, 0, 0
Tuttavia con Clang (3.6.1), l'uscita è diverso:
0, 1, 1, 2, 0, 0
0, 1, 1, 2, 0, 0
5, 2, 2, 3, 5, 5
In particolare, gli indici generati per tipi di funzione locale (es. 'Z') fai qualcosa di strano. È come se incrementassero e riassegnassero l'indice ogni volta che viene chiamato Component<Z,...>
.
Perché succede? È un bug del compilatore? Ci sono delle considerazioni particolari quando si usano i tipi locali di funzione con i template (post C++ 11)?
Un esempio completo può essere trovato qui: http://coliru.stacked-crooked.com/a/7fcb989ae6eab476
== Modifica ==
ho deciso di postare la questione del clang bugtracker, quindi se qualcun altro si imbatte in questo:
https://llvm.org/bugs/show_bug.cgi?id=24048
Esso si presenta come clang si aspetta l'espressione di inizializzazione per 'componente :: index' a sii puro Rimuovendo l'identificatore 'const' su' index' si ottiene il [risultato previsto] (http://coliru.stacked-crooked.com/a/bc8c910192a2ee67). –
Pradhan
Non sono del tutto sicuro se questo programma è ben formato; forse è ben formato ma l'output non è specificato. Ad esempio, le diverse istanze del membro dei dati statici dovrebbero avere un'inizializzazione non ordinata. L'ordine di inizializzazione determina tuttavia l'output del programma. – dyp
Inoltre non è chiaro se l'ordine delle istanze all'interno della funzione è ben definito. Tuttavia, non vedo alcun motivo per il '5' o' 3' di apparire nell'output (che richiederebbe UB credo, e non vedo nessun UB qui, solo un ordine non specificato). Vedi anche https://groups.google.com/a/isocpp.org/d/msg/std-discussion/M6aJMH_ewoM/BpXj_heDGjMJ – dyp