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(...)
?
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 :("
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
.
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.
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.
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.
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");
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");
// ...
}
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