Vous pourriez vous passer d'un en-tête:
using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); // The shortest is my favourite.
using size_t = decltype(sizeof "anything");
En effet, la norme C ++ requiert:
Le résultat de sizeof
et sizeof...
est une constante de type std::size_t
. [Remarque: std::size_t
est défini dans l'en-tête standard <cstddef>
(18.2). - note de fin]
En d'autres termes, la norme exige:
static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
"This never fails.");
Notez également qu'il est parfaitement bien de faire cette typedef
déclaration dans l' std
espace de noms global et dans , tant qu'elle correspond à toutes les autres typedef
déclarations du même typedef-name (une erreur de compilation est émise sur les déclarations non correspondantes).
Ceci est dû au fait:
§7.1.3.1 Un typedef-name n'introduit pas de nouveau type comme le fait une déclaration de classe (9.1) ou une déclaration enum.
§7.1.3.3 Dans une portée non-classe donnée, un typedef
spécificateur peut être utilisé pour redéfinir le nom de tout type déclaré dans cette portée pour faire référence au type auquel il fait déjà référence.
Aux sceptiques disant que cela constitue un ajout d'un nouveau type dans l'espace de noms std
, et qu'un tel acte est explicitement interdit par la norme, et c'est UB et c'est tout là-dedans; Je dois dire que cette attitude revient à ignorer et à nier une compréhension plus profonde des problèmes sous-jacents.
Le standard interdit l'ajout de nouvelles déclarations et définitions dans l'espace de noms std
car, ce faisant, l'utilisateur peut faire un désordre de la bibliothèque standard et lui tirer dessus toute sa jambe. Pour les rédacteurs standard, il était plus facile de laisser l'utilisateur se spécialiser dans certaines choses spécifiques et interdire de faire quoi que ce soit d'autre pour faire bonne mesure, plutôt que d'interdire chaque chose que l'utilisateur ne devrait pas faire et risquerait de manquer quelque chose d'important (et cette étape). Ils l'ont fait dans le passé en exigeant qu'aucun conteneur standard ne soit instancié avec un type incomplet, alors qu'en fait certains conteneurs pourraient bien le faire (voir The Standard Librarian: Containers of Incomplete Types par Matthew H.Austern ):
... En fin de compte, tout cela semblait trop trouble et trop mal compris; le comité de normalisation n'a pas pensé qu'il y avait d'autre choix que de dire que les conteneurs STL ne sont pas censés fonctionner avec des types incomplets. Pour faire bonne mesure, nous avons également appliqué cette interdiction au reste de la bibliothèque standard.
... Rétrospectivement, maintenant que la technologie est mieux comprise, cette décision semble encore fondamentalement juste. Oui, dans certains cas, il est possible d'implémenter certains des conteneurs standard afin qu'ils puissent être instanciés avec des types incomplets - mais il est également clair que dans d'autres cas, ce serait difficile, voire impossible. C'était surtout par hasard que le premier test que nous avons essayé, en utilisant std::vector
, se soit avéré être l'un des cas faciles.
Étant donné que les règles linguistiques exigent std::size_t
d'être exactes decltype(sizeof(int))
, faire namespace std { using size_t = decltype(sizeof(int)); }
est l'une de ces choses qui ne cassent rien.
Avant C ++ 11, il n'y avait pas decltype
et donc aucun moyen de déclarer le type de sizeof
résultat en une seule instruction simple sans impliquer un grand nombre de modèles. size_t
alias différents types sur différentes architectures cibles, cependant, ce ne serait pas une solution élégante d'ajouter un nouveau type intégré uniquement pour le résultat de sizeof
, et il n'y a pas de typedefs standard intégrés. Par conséquent, la solution la plus portable à l'époque était de mettre size_t
un alias de type dans un en-tête spécifique et de le documenter.
En C ++ 11, il existe maintenant un moyen d'écrire cette exigence exacte de la norme comme une simple déclaration.