2013-07-23 13 views
10

W rozmowie kwalifikacyjnej poproszono mnie o napisanie metafunkcji , która określiła, czy typ był wskaźnikiem. To co przedstawiłem:Jak mogę tworzyć asercje czasu kompilacji bez C++ 11

template <typename T> 
struct is_pointer 
{ static const bool value = false; } 

template <typename T> 
struct is_pointer<T *> 
{ static const bool value = true; } 

Potem został poproszony o napisanie meta-assert, że zawiedzie podczas kompilacji, jeśli mój is_pointer funkcja nie jest postępuje słusznie.

Kiedy użyłem static_assert, wyraźnie powiedział mi, że mogę używać tylko standardu C++ 98. Jak mogę to osiągnąć?

+8

myślę w tym momencie zdałeś „Sprawdź aby sprawdzić, czy rzeczywiście znasz język "część wywiadu, chyba że firma tworzy kompilatory C++ lub coś takiego. –

Odpowiedz

5

W twoim przypadku

template <bool> struct assert; 
template <> struct assert<true> {}; 

byłby rozwiązany problem:

assert<!is_pointer<char>::value>();  // valid 
assert<is_pointer<char *>::value>(); // valid 

assert<is_pointer<char>::value>();  // compilation error: 
             // use of incomplete class 
+0

To nie jest SFINAE (rozwiązanie jest w porządku, ale nazwa jest nadużywana). –

+0

Ogranicza się to również do miejsc, w których można utworzyć obiekt tego typu. Aby móc go używać w innych kontekstach, musiałbyś stworzyć fałszywe obiekty: '// namespace: assert myassert;' –

9

Istnieją różne podejścia, wspólna jeden próbuje typedef niepoprawny typ:

#define static_assert(condition) \ 
     typedef char assert ## __LINE__ [((condition)?1:-1)] 

ten może być użyty w większości kontekstów i wywoła kompilator, jeśli warunek jest fałszywy, ponieważ próbowałby typować a n nieprawidłowy typ (tablica ujemnej liczby elementów). Może być używany w różnych kontekstach:

// namespace level: 
static_assert(sizeof(int)==4); 
struct type { 
    // class level: 
    static_assert(sizeof(int)==4); 
    void f() { 
     // function level 
     static_assert(sizeof(int)==4); 
    } 
}; 
+3

Ten może być nawet użyty w czystym C :) Ale pamiętaj, że przy aktualnym makrze typedef będzie zawsze "assert__LINE__", tak jak jest; aby rozwinąć '__LINE__' do rzeczywistego numeru linii, potrzebujesz pośredniego wywołania makr" join ": [Co należy zrobić z makrami, które wymagają wklejenia dwóch tokenów?] (http://www.parashift.com/c++fafaq /macros-with-token-pasting.html) –

3

Chciałbym użyć BOOST_STATIC_ASSERT. Możesz spojrzeć na kod: boost/static_assert.hpp.

Oto bardzo uproszczona wersja, po prostu daje wyobrażenie:

#define JOIN(X, Y) DO_JOIN(X, Y) 
#define DO_JOIN(X, Y) X ## Y 

template<bool cond> 
struct Static_assert_helper; // incomplete type 

template<> 
struct Static_assert_helper<true> { 
    typedef int Type; 
}; 

#define STATIC_ASSERT(cond) \ 
    typedef Static_assert_helper<(cond)>::Type JOIN(Static_assert_typedef_, __LINE__) 

może być używany w wielu miejscach (patrz dokumentacja przykłady).

(realizacja Boost jest bardziej kompletny, ze np sizeof i pośrednim struct, aby dać lepszą komunikat o błędzie i być przenośne na wielu kompilatorów).

Powiązane problemy