2013-07-16 10 views
7

Próbuję zrozumieć przydatność static_assert i chcę wiedzieć, czy może mi pomóc w egzekwowaniu projekt, a jeśli tak, to w jaki sposób.Wymuszanie typ szablonu poprzez static_assert

Mam ogólną klasę szablonu, który ukrywa swoją własną implementację wewnątrz innej klasy szablonu, który jest częściowo specjalizującej się w zależności od wielkości, typu szablonu. Oto krótki zarys tego projektu:

template <class T, size_t S = sizeof(T)> 
struct Helper; 

template <class T> 
struct Helper<T, sizeof(long)> 
{ 
    static T bar(); 
}; 

// ... other specializations ... 

template <class T> 
class Foo 
{ 
public: 

    T bar() 
    { 
     return Helper<T>::bar(); 
    } 
}; 

Foo jest obsługiwana tylko wtedy, gdy wielkość T jest wspierany przez specjalizacji Helper. Obsługiwane są na przykład Foo<long> i Foo<unsigned long>. Załóżmy jednak, że użytkownik próbuje zbudować model Foo<bool>. Zazwyczaj będzie to generować błędy, ponieważ specjalizacja Helper dla bool nie jest zdefiniowany, który jest przeznaczony zachowanie.

Czy jest jakiś sposób na wykorzystanie static_assert w tej konstrukcji w celu zapewnienia bardziej pomocny błędy użytkownikowi tego interfejsu?

Dodatkowo chciałbym również restric użytkownikowi korzystanie z konkretnego rodzaju, mimo że wielkość może być prawidłowa. Na przykład: Foo<float> nie powinno być dozwolone. W tej chwili jedynym sposobem, w jaki wiem o egzekwowaniu tego jest odważny komentarz w dokumentacji. :)

+0

Myśleć bardziej ogólnie, czy to tylko typy liczb całkowitych, które są obsługiwane? Nie 'char',' bool', 'float', et al? – Rapptz

+0

Wyszukaj SO dla ograniczeń typu szablonu lub "pojęć". Obiekt do tego został usunięty z C++ 11 w ostatniej chwili. Istnieją jednak mniej automatyczne sposoby osiągnięcia podobnych rezultatów. – luke

+0

@Rapptz, 'char',' int' i 'long', wraz z ich wersjami' unsigned' powinny być obsługiwane. Kod byłby identyczny dla 'int',' long' i 'unsigned long' jeśli' sizeof (int) == sizeof (long) == sizeof (unsigned long) '. – Zeenobit

Odpowiedz

1

zorientowali się lepsze rozwiązanie tego problemu poprzez łączenie odpowiedzi i komentarze.

mogę określić statyczny typ sprawdzania tak:

template <class A, class B> 
struct CheckTypes 
{ 
    static const bool value = false; 
}; 

template <class A> 
struct CheckTypes<A, A> 
{ 
    static const bool value = true; 
}; 

Nie wiem, czy taka struktura już istnieje w bibliotece standardowej.Tak czy inaczej, to w Foo, mogę sprawdzić typów i rozmiarów przy użyciu:

static_assert((sizeof(T) == sizeof(long) || sizeof(T) == sizeof(int)) && !CheckTypes<T, float>::value, "Error!"); 
+1

to robi, std :: is_same –

+1

użycie sizeof nie jest bezpieczne. to tylko rozmiar. long i int mogą być tego samego rozmiaru, a losowa struktura, która zawiera tylko int, również będzie miała ten sam rozmiar. –

13

Jeśli może pracować tylko na specjalizacji szablonu klasy, wtedy domyślna klasa szablon podnieść statyczny assert:

template <class T, size_t S = sizeof(T)> 
struct Helper 
{ 
    static_assert(sizeof(T) == -1,"You have to have a sepecialization for Helper!"); 
} 

Klasa domyślny szablon zostanie wybrany tylko wtedy, gdy nie ma lepsza specjalizacja, dlatego wzrośnie twierdzenie.

można użyć tej samej techniki, aby uniemożliwić typy, ale trzeba inny parametr szablonu, który będzie używany do sprawdzania statycznego assert.

template <class T, class G = T, size_t S = sizeof(T)> 
struct Helper 
{ 
    static_assert(sizeof(G) == -1,"You have to have a sepecialization for Helper!"); 
} 

template <class G> 
struct Helper<float,G> 
{ 
    static_assert(sizeof(G) == -1,"You can't use float !"); 
} 

template <> 
struct Helper<int> 
{ 
//This is a good specialization 
}; 

Następnie można spróbować z tych zmiennych:

Helper<bool> a; //"You have to have a sepecialization for Helper!" 
Helper<float> b; //"You can't use float !" 
Helper<int> c; //compiles OK 
+1

Wierzę, że chcesz 'static_assert (false, ...)', więc zawsze wyskakuje. 'static_assert' drukuje błąd, jeśli pierwszy argument jest fałszywy. –

+0

+1 dla pragmatycznej odpowiedzi – sehe

+9

To nie zadziała tak jak jest - musisz uzależnić to stwierdzenie (na przykład 'static_assert (sizeof (T) == 0, ...);'), w przeciwnym razie zostanie przetworzone na punkt deklaracji, a nie tworzenie instancji. – Angew

3

http://en.cppreference.com/w/cpp/header/type_traits

std::is_base_of i std::is_convertible mogłyby pomóc w pierwszym numerze, jak i dla drugiej,

static_assert(!std::is_same<float,T>(),"type can't be float");

mam nadzieję, że pomoże to komuś innemu, kto natknie się na to pytanie, zakładając, że OP prawdopodobnie znalazł odpowiedź w ciągu 4 lat grzechu ce to było pytanie :)

Powiązane problemy