Question

Pouvez-vous donner un exemple où static_assert (...) 'C ++ 0x' résoudrait le problème de façon élégante?

Je connais bien l'exécution assert (...) au moment de l'exécution. Quand devrais-je préférer static_assert (...) par rapport à assert (...) ?

De plus, dans boost , il existe un élément appelé BOOST_STATIC_ASSERT . Est-ce la même chose que static_assert (...) ?

Était-ce utile?

La solution

Comme si de rien n'était ...

#include "SomeLibrary.h"

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

class UsingSomeLibrary {
   // ...
};

En supposant que SomeLibrary :: Version soit déclaré en tant que const statique, plutôt que #define d (comme on pourrait s'y attendre dans une bibliothèque C ++).

Contrastez avec le fait de devoir compiler SomeLibrary et votre code, liez le tout et exécutez uniquement l'exécutable puis pour découvrir que vous avez passé 30 minutes à compiler une version incompatible de SomeLibrary .

@Arak, en réponse à votre commentaire: oui, vous pouvez laisser static_assert simplement à l'extérieur, où que vous soyez:

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 :("

Autres conseils

L'assertion statique est utilisée pour faire des assertions au moment de la compilation. Lorsque l'assertion statique échoue, le programme ne compile tout simplement pas. Cela est utile dans différentes situations, par exemple si vous implémentez des fonctionnalités par un code qui dépend de manière critique d'un objet unsigned int ayant exactement 32 bits. Vous pouvez mettre une assertion statique comme ceci

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

dans votre code. Sur une autre plate-forme, avec un type unsigned int de taille différente, la compilation échouera, attirant ainsi l'attention du développeur sur la partie problématique du code et lui conseillant de le réimplémenter ou de le réinspecter.

Pour un autre exemple, vous pouvez passer une valeur intégrale en tant que pointeur void * à une fonction (un hack, mais utile parfois) et vous assurer que la valeur intégrale tenir dans le pointeur

int i;

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

Vous voudrez peut-être que ce type char soit signé

.
static_assert(CHAR_MIN < 0);

ou cette division intégrale avec des valeurs négatives arrondit à zéro

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

Et ainsi de suite.

Dans de nombreux cas, les assertions d'exécution peuvent être utilisées à la place des assertions statiques, mais les assertions d'exécution ne fonctionnent qu'au moment de l'exécution et uniquement lorsque le contrôle passe sur l'assertion. Pour cette raison, une assertion d'exécution défaillante peut rester en sommeil, sans être détectée pendant de longues périodes.

Bien sûr, l’expression dans une assertion statique doit être une constante de compilation. Ce ne peut pas être une valeur d'exécution. Pour les valeurs d'exécution, vous n'avez pas d'autre choix que d'utiliser l'habituel assert .

Je l'utilise pour m'assurer que mes hypothèses sur le comportement du compilateur, les en-têtes, les bibliothèques et même mon propre code sont correctes. Par exemple ici, je vérifie que la structure a été correctement compressée à la taille attendue.

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

Dans une classe encapsulant le fseek () de stdio.h , j'ai pris des raccourcis avec enum Origine et vérifiez que ces raccourcis aligner avec les constantes définies par stdio.h

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

Vous devriez préférer static_assert à assert lorsque le comportement est défini au moment de la compilation, et non au moment de l'exécution, comme dans les exemples que j'ai donnés ci-dessus. Un exemple où pas il s’agit de vérifier les paramètres et les codes de retour.

BOOST_STATIC_ASSERT est une macro pré-C ++ 0x qui génère un code non autorisé si la condition n'est pas remplie. Les intentions sont les mêmes, mais static_assert est normalisé et peut fournir de meilleurs diagnostics pour le compilateur.

BOOST_STATIC_ASSERT est un wrapper multiplateforme pour la fonctionnalité static_assert .

J'utilise actuellement static_assert pour appliquer les "Concepts". sur une classe.

exemple:

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 ... */
};

Ceci provoquera une erreur de temps de compilation si l’une des conditions ci-dessus n’est pas remplie.

Une des utilisations de static_assert pourrait être de s'assurer qu'une structure (c'est-à-dire une interface avec le monde extérieur, telle qu'un réseau ou un fichier) a exactement la taille que vous attendez. Cela concernerait les cas où quelqu'un ajoute ou modifie un membre de la structure sans se rendre compte des conséquences. Le static_assert le capturerait et avertirait l'utilisateur.

En l'absence de concepts, vous pouvez utiliser static_assert pour une vérification de type simple et lisible au moment de la compilation, par exemple, dans les modèles:

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

// ...
}

Cela ne répond pas directement à la question initiale, mais constitue une étude intéressante sur la façon de faire appliquer ces contrôles de compilation avant C ++ 11.

Le chapitre 2 (section 2.1) de la conception en C ++ moderne par Andrei Alexanderscu l'implémente idée d'assertions de temps de compilation comme ceci

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

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

Comparez les macros STATIC_CHECK () et static_assert ()

STATIC_CHECK(0, COMPILATION_FAILED);
static_assert(0, "compilation failed");
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top