Introduction▲
L'en-tête <boost/static_assert.hpp> fournit une simple macro BOOST_STATIC_ASSERT(x) qui génère un message d'erreur si l'expression entière constante x ne vaut pas true. C'est donc l'équivalent à la compilation de la macro assert. Lors de la compilation, si la génération est effectuée, la classe est vide et donc ne prend pas de place mémoire. De même, la macro n'est évaluée que lors de l'instanciation, donc pas de problème avec les classes templates.
On va regarder son utilisation à quatre emplacements, dans un espace de noms, dans une fonction, dans une classe et dans des templates.
I. Utilisation dans un espace de noms▲
Ici, la macro sera toujours instanciée. Cela signifie que les assertions dans les espaces de noms servent à vérifier les impératifs de la plateforme - taille d'un int, version d'une bibliothèque… -. Comme la macro BOOST_STATIC_ASSERT(x) est en fait un typedef avec l'utilisation de la macro _LINE_, l'utilisation dans un espace de noms peut entraîner la duplication des typedefs et dans certains cas des warnings, donc utilisez un espace de nom particulier pour tester ces conditions, et dans un seul fichier d'en-tête.
#include
<boost/static_assert.hpp>
namespace
conditions
{
BOOST_STATIC_ASSERT(sizeof
(char
)==
1
);
}
II. Utilisation dans une fonction▲
Dans le cadre des fonctions, on pense principalement aux fonctions templates. Cela permet, logiquement, de vérifier le type des données passées en paramètres, comme la vérification de capacités telle la conversion vers un type dont on connait les caractéristiques – itérateurs à accès aléatoire –, la taille…
#include
<boost/static_assert.hpp>
template
<
typename
T>
T test(const
&
T)
{
BOOST_STATIC_ASSERT(sizeof
(T)>
1
);
return
T;
}
III. Utilisation dans une classe▲
L'utilisation dans une classe a les mêmes capacités que l'utilisation dans le cadre d'une fonction.
#include
<boost/static_assert.hpp>
template
<
typename
T>
class
test
{
BOOST_STATIC_ASSERT(sizeof
(T)>
1
);
public
:
test(const
&
T)
{
// ...
}
}
IV. Utilisation dans un template▲
Lors de l'utilisation dans un template, normalement l'erreur ne survient qu'à l'instanciation. Malheureusement, certains compilateurs ne fonctionnent pas ainsi. Par exemple, ce code :
template
<
class
T>
struct
must_not_be_instantiated
{
BOOST_STATIC_ASSERT(false
);
}
;
Produit une erreur et on est obligé de le remplacer par :
template
<
class
T>
struct
must_not_be_instantiated
{
BOOST_STATIC_ASSERT(sizeof
(T) ==
0
);
}
;
On voit ici qu'une telle assertion peut aussi être utilisée pour empêcher l'utilisation d'une classe template non spécialisée.
Conclusion▲
La simplicité et la légèreté de cette macro font qu'on devrait l'utiliser partout où une assertion effectuée par assert pourrait être faite à la compilation. Même si c'est rare, on gagne du temps, car l'assertion est à la compilation, non pas à l'exécution. De même, l'assertion est plus générale, car elle vaut sur toutes les possibilités des données en entrée et non pas dans un cas d'utilisation comme c'est le cas des assertions à l'exécution. Enfin, c'est la seule manière de vérifier qu'on instancie bien le bon type de données.