Co robi static assert i do czego byś go użył?

Mógłby Pan podać przykład, gdzie static_assert(...) 'C++0x' rozwiązałby ten problem w sposób elegancki?

Jestem zaznajomiony z run-time assert(...). Kiedy powinienem wybrać static_assert(...) zamiast zwykłego assert(...)?

Również w boost istnieje coś o nazwie BOOST_STATIC_ASSERT, czy to to samo co static_assert(...)?

Author: AraK, 2009-10-30

7 answers

Off the top of My head...

#include "SomeLibrary.h"

static_assert(SomeLibrary::Version > 2, 
         "Old versions of SomeLibrary are missing the foo functionality.  Cannot proceed!");

class UsingSomeLibrary {
   // ...
};

Zakładając, że SomeLibrary::Version jest zadeklarowana jako statyczny const, a nie #define d (jak można by się spodziewać w bibliotece C++).

W przeciwieństwie do konieczności kompilacji SomeLibrary i kodu, łączenia wszystkiego i uruchamiania tylko , a następnie, aby dowiedzieć się, że spędziłeś 30 minut kompilując niezgodną wersję SomeLibrary.

@Arak, w odpowiedzi na twój komentarz: tak, możesz mieć static_assert po prostu siedzieć gdziekolwiek, z wyglądu

class Foo
{
    public: 
        static const int bar = 3;
};

static_assert(Foo::bar > 4, "Foo::bar is too small :(");

int main()
{ 
    return Foo::bar;
}
$ g++ --std=c++0x a.cpp
a.cpp:7: error: static assertion failed: "Foo::bar is too small :("
 60
Author: Mark Rushakoff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-30 04:01:22

Static assert jest używany do tworzenia twierdzeń w czasie kompilacji. Gdy twierdzenie statyczne nie powiedzie się, program po prostu nie kompiluje się. Jest to przydatne w różnych sytuacjach, na przykład, jeśli zaimplementujesz jakąś funkcjonalność za pomocą kodu, który krytycznie zależy od unsigned int obiektu mającego dokładnie 32 bity. Możesz umieścić twierdzenie statyczne w ten sposób

static_assert(sizeof(unsigned int) * CHAR_BIT == 32);

W Twoim kodzie. Na innej platformie, z innym typem unsigned int Kompilacja się nie powiedzie, tym samym zwracając uwagę dewelopera na problematyczna część kodu i doradzanie im, aby ponownie go zaimplementowali lub skontrolowali.

W innym przykładzie możesz przekazać pewną wartość całki jako wskaźnik void * do funkcji (hack, ale czasami przydatny) i chcesz się upewnić, że wartość całki będzie pasować do wskaźnika

int i;

static_assert(sizeof(void *) >= sizeof i);
foo((void *) i);

Możesz chcieć dodać, że char typ jest podpisany

static_assert(CHAR_MIN < 0);

Lub że Całka z wartościami ujemnymi zaokrągla się do zera

static_assert(-5 / 2 == -2);

I tak on

Twierdzenia Run-time w wielu przypadkach mogą być używane zamiast twierdzeń statycznych, ale twierdzenia run-time działają tylko w czasie run-time I tylko wtedy, gdy kontrola przechodzi nad twierdzeniem. Z tego powodu nieudane twierdzenie run-time może leżeć uśpione, niewykryte przez dłuższy czas.

Oczywiście wyrażenie w twierdzeniu statycznym musi być stałą czasu kompilacji. To nie może być wartość run-time. Dla wartości run-time nie masz innego wyboru, jak użyć zwykłego assert.

 108
Author: AnT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-30 04:03:16

Używam go, aby upewnić się, że moje założenia dotyczące zachowania kompilatora, nagłówków, bibliotek, a nawet własnego kodu są poprawne. Na przykład tutaj sprawdzam, czy struktura została poprawnie spakowana do oczekiwanego rozmiaru.

struct LogicalBlockAddress
{
#pragma pack(push, 1)
    Uint32 logicalBlockNumber;
    Uint16 partitionReferenceNumber;
#pragma pack(pop)
};
BOOST_STATIC_ASSERT(sizeof(LogicalBlockAddress) == 6);

W Class wrapping stdio.h's fseek(), wziąłem kilka skrótów z enum Origin i sprawdzić, czy te skróty są zgodne ze stałymi zdefiniowanymi przez stdio.h

uint64_t BasicFile::seek(int64_t offset, enum Origin origin)
{
    BOOST_STATIC_ASSERT(SEEK_SET == Origin::SET);

Powinieneś preferować static_assert zamiast assert, gdy zachowanie jest zdefiniowane w czasie kompilacji, a nie w czasie wykonywania, takie jak przykłady, które podałem powyżej. Przykład, gdzie jest to , a nie przypadek obejmowałby sprawdzanie parametrów i kodu zwrotnego.

BOOST_STATIC_ASSERT jest makrem pre-C++0x, które generuje nielegalny Kod, jeśli warunek nie jest spełniony. Intencje są takie same, aczkolwiek static_assert jest znormalizowany i może zapewnić lepszą diagnostykę kompilatora.

 11
Author: Matt Joiner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-30 10:28:49

BOOST_STATIC_ASSERT jest wieloplatformowym opakowaniem dla static_assert funkcjonalności.

Obecnie używam static_assert w celu wymuszenia "pojęć" na klasie.

Przykład:

template <typename T, typename U>
struct Type
{
  BOOST_STATIC_ASSERT(boost::is_base_of<T, Interface>::value);
  BOOST_STATIC_ASSERT(std::numeric_limits<U>::is_integer);
  /* ... more code ... */
};

Spowoduje to błąd w czasie kompilacji, jeśli którykolwiek z powyższych warunków nie jest spełniony.

 9
Author: nurettin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-12 12:18:36

Jednym z zastosowań static_assert może być zapewnienie, że struktura (która jest interfejsem ze światem zewnętrznym, takim jak sieć lub plik) ma dokładnie taki rozmiar, jakiego oczekujesz. To wychwyciłoby przypadki, w których ktoś dodaje lub modyfikuje członka ze struktury bez uświadamiania sobie konsekwencji. static_assert podniesie go i zaalarmuje użytkownika.

 4
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-30 03:43:31

To nie odpowiada bezpośrednio na oryginalne pytanie, ale robi interesujące badanie, jak wymusić te kontrole czasu kompilacji przed C++11.

Rozdział 2 (sekcja 2.1) Modern C++ Design by Andrei Alexanderscu implementuje tę ideę twierdzeń w czasie kompilacji, jak to

template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};

#define STATIC_CHECK(expr, msg) \
{ CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } 

Porównaj makro STATIC_CHECK () i static_assert()

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");
 2
Author: nightlytrails,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-02 03:53:42

W przypadku braku pojęć można użyć static_assert do prostego i czytelnego sprawdzania typu w czasie kompilacji, na przykład w szablonach:

template <class T>
void MyFunc(T value)
{
static_assert(std::is_base_of<MyBase, T>::value, 
              "T must be derived from MyBase");

// ...
}
 2
Author: vladon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-14 20:54:39