2013-08-11 5 views
5

Ho il seguente codice:non di tipo argomento di un template non è un'espressione costante

#include <cstdlib> 
#include <cstdio> 
#include <atomic> 

enum ATYPE { Undefined = 0, typeA, typeB, typeC }; 

template<ATYPE TYPE = Undefined> 
struct Object 
{ 
    Object() { counter++; } 
    static std::atomic<int> counter; 
}; 

template<ATYPE TYPE> 
std::atomic<int> Object<TYPE>::counter(1); 

template<ATYPE TYPE> 
void test() 
{ 
    printf("in test\n"); 
    Object<TYPE> o; 
} 

int main(int argc, char **argv) 
{ 
    test<typeA>(); 
    printf("%d\n", Object<typeA>::counter.load()); 
    Object<typeA>::counter.store(0); 
    for (int i = 0; i < sizeof(ATYPE); ++i) { 
     Object<static_cast<ATYPE>(i)>::counter.store(0); 
    } 
    return 0; 
} 

Quando compilo con la seguente riga di comando:

clang++ -o test -std=c++11 -stdlib=libc++ test.cpp 

Ottengo i seguenti errori:

test.cpp:32:20: error: non-type template argument is not a constant expression 
Object<static_cast<ATYPE>(i)>::counter.store(0); 
^~~~~~~~~~~~~~~~~~~~~ 
test.cpp:32:39: note: read of non-const variable 'i' is not allowed in a constant expression 
Object<static_cast<ATYPE>(i)>::counter.store(0); 
^ 
testray.cpp:31:18: note: declared here 
for (int i = 0; i < sizeof(ATYPE); ++i) { 

Capisco il problema in cui credo. L'argomento del modello deve essere un constexpr e chiaramente non lo è. Quindi la domanda è, sono possibili modifiche che posso fare per farlo funzionare. Con questo lavoro, voglio dire, posso in qualche modo avere un modo migliore di reimpostare questi contatori statici da questa classe modello per ogni tipo in ATYPE, diversi dal semplice farlo manualmente:

Object<Undefined>::counter.store(0); 
Object<typeA>::counter.store(0); 
... 

che non è così elegante e pratico quando ATYPE contiene molti tipi.

Grazie mille per il vostro aiuto e consigli.

+1

In ogni caso, stai scorrendo il tuo enum. 'i' non è un'espressione costante neanche come mostra l'errore. – Rapptz

+0

@Rapptz, potresti per favore essere più specifico sul tuo primo commento (scorrendo l'enum sbagliato). So che non sono const, quindi è per questo che sto chiedendo se c'è un modo per farlo funzionare. C'è un modo per aggirare tutti gli elementi dell'enumerazione e azzerare i contatori? grazie. – user18490

+0

Ciò che Rapptz significa è che i è dinamico e non può essere usato come argomento del modello di compilazione tempo –

risposta

7

Per questo genere di cose, la ricorsione è tipicamente una soluzione semplice:

#include <type_traits> 

enum ATYPE { Undefined = 0, typeA, typeB, typeC, ATYPE_END }; 

void reset_Object_counter(std::integral_constant<ATYPE, ATYPE_END>) 
{} 

template < ATYPE n = Undefined > 
void reset_Object_counter(std::integral_constant<ATYPE, n> p = {}) 
{ 
    Object<p>::counter.store(0); 
    reset_Object_counter(std::integral_constant<ATYPE, 
               static_cast<ATYPE>(n+1)>{}); 
} 

Per questo caso, per quanto ne so, funzione di modello di specializzazione funziona così (al posto del primo sovraccarico):

template<> 
void reset_Object_counter<ENUM_END>(std::integral_constant<ATYPE, ENUM_END>) 
{} 

In entrambi i casi, l'utilizzo è solo reset_Object_counter(); per impostare tutti i contatori Object<...> su 0.


La soluzione integral_constant è in realtà un po 'eccessivo qui, per questo problema un parametro di modello non-tipo è sufficiente (perché la funzione di modello di specializzazione può prendere il posto del sovraccarico porre fine alla ricorsione).

template < ATYPE n = Undefined > 
void reset_Object_counter() 
{ 
    Object<n>::counter.store(0); 
    reset_Object_counter<static_cast<ATYPE>(n+1)>(); 
} 
template<> 
void reset_Object_counter<ENUM_END>() 
{} 
+0

Fantastico. È lì che mi rendo conto di non conoscere abbastanza il C++. Non ho mai sentito di integral_constant ... ma sto recuperando tutte le nuove cose che possiamo trovare in C++ 11 e sembra che possa richiedere una vita intera. Grazie mille buona risposta, e grazie a tutti gli altri. – user18490

+0

@ user18490 Il 'integral_constant' non è nemmeno richiesto qui;) – dyp

+0

sì, in effetti sto provando a scrivere il codice senza, perché ho indovinato potrebbe funzionare senza, ma ero comunque felice di imparare qualcosa. Grazie per questa osservazione aggiunta. – user18490