2013-08-11 11 views
5

Mam następujący kod:dla typu szablonu argument nie jest stałym wyrażeniem

#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; 
} 

Kiedy skompilować z poniższej linii poleceń:

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

otrzymuję następujące błędy:

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) { 

Rozumiem problem, w który wierzę. Argument szablonu musi być constexpr i wyraźnie nie jest. Pytanie brzmi, czy są możliwe zmiany, które mogę zrobić, aby to zadziałało. Przez to działa, to znaczy, czy mogę jakoś ma lepszego sposobu resetowania tych statycznych liczników z tej klasy szablonu dla każdego typu w Atype, inne niż po prostu robi to ręcznie:

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

co nie jest tak elegancki i praktyczny gdy ATYPE zawiera wiele typów.

Bardzo dziękuję za pomoc i porady.

+1

Tak czy inaczej, przeplatasz swoje wyliczenie. 'i' nie jest stałym wyrażeniem, tak jak pokazuje błąd. – Rapptz

+0

@Rapptz, czy mógłbyś bardziej szczegółowo opisać swój pierwszy komentarz (niepoprawne wyliczenie enum). Wiem, że nie jestem const, więc dlatego pytam, czy jest jakiś sposób na zrobienie tego dzieła. Czy istnieje sposób na zapętlenie wszystkich elementów wyliczenia i zresetowanie liczników? Dziękuję Ci. – user18490

+0

Co oznacza, że ​​Rapptz jest dynamiczny i nie może być użyty jako szablon szablonu czasu kompilacji –

Odpowiedz

7

Dla tego rodzaju rzeczy, rekurencja jest zazwyczaj proste rozwiązanie:

#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)>{}); 
} 

W tym przypadku, AFAIK, szablon funkcja specjalizacja działa tak samo (zamiast pierwszego przeciążenia):

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

Tak czy inaczej, użycie to tylko reset_Object_counter();, aby ustawić wszystkie liczniki Object<...> na 0.


Rozwiązanie integral_constant jest rzeczywiście trochę przesadą tutaj tego problemu parametrem szablonu non-type jest wystarczający (ponieważ specjalizacja szablonu funkcja może zająć miejsce przeciążenia kończącego rekurencji).

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

Fantastyczne. Tam zdaję sobie sprawę, że nie znam wystarczająco C++. Nigdy nie słyszałem o integral_constant ... ale nadrabiam wszystkie nowe rzeczy, które możemy znaleźć w C++ 11 i wydaje się, że może to zająć całe życie. Dziękuję bardzo dobrą odpowiedzią i wszystkim innym. – user18490

+0

@ user18490 'integral_constant' nie jest tu nawet wymagany;) – dyp

+0

Tak, tak naprawdę próbuję napisać kod bez, ponieważ domyślam się, że może on działać bez, ale i tak cieszę się, że mogę się czegoś nauczyć. Dziękujemy za tę uwagę dodatkową. – user18490

Powiązane problemy