Podrías prescindir de un encabezado:
using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); // The shortest is my favourite.
using size_t = decltype(sizeof "anything");
Esto se debe a que el estándar C ++ requiere:
El resultado de sizeof
y sizeof...
es una constante de tipo std::size_t
. [Nota: std::size_t
se define en el encabezado estándar <cstddef>
(18.2). - nota final]
En otras palabras, el estándar requiere:
static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
"This never fails.");
También tenga en cuenta que está perfectamente bien hacer esta typedef
declaración en el std
espacio global y en el espacio de nombres, siempre que coincida con todas las demás typedef
declaraciones del mismo typedef-name (se emite un error del compilador en declaraciones que no coinciden).
Esto es porque:
§7.1.3.1 Un typedef-name no introduce un nuevo tipo como lo hace una declaración de clase (9.1) o una declaración de enumeración.
§7.1.3.3 En un ámbito que no sea de clase dado, typedef
se puede usar un especificador para redefinir el nombre de cualquier tipo declarado en ese ámbito para hacer referencia al tipo al que ya se refiere.
A los escépticos que dicen que esto constituye una adición de un nuevo tipo en el espacio de nombres std
, y tal acto está explícitamente prohibido por el estándar, y esto es UB y eso es todo; Debo decir que esta actitud equivale a ignorar y negar una comprensión más profunda de los problemas subyacentes.
El estándar prohíbe agregar nuevas declaraciones y definiciones en el espacio de nombres std
porque al hacerlo el usuario puede hacer un lío de la biblioteca estándar y dispararse. Para los escritores estándar, era más fácil dejar que el usuario se especializara en algunas cosas específicas y prohibir hacer cualquier otra cosa por si acaso, en lugar de prohibir todo lo que el usuario no debería hacer y arriesgarse a perderse algo importante (y esa pierna). Lo hicieron en el pasado cuando requerían que ningún contenedor estándar se instanciara con un tipo incompleto, mientras que, de hecho, algunos contenedores podrían funcionar bien (ver The Standard Librarian: Containers of Incomplete Types por Matthew H. Austern ):
... Al final, todo parecía demasiado turbio y mal entendido; el comité de estandarización no pensó que había otra opción excepto decir que los contenedores STL no deben funcionar con tipos incompletos. Por si acaso, también aplicamos esa prohibición al resto de la biblioteca estándar.
... En retrospectiva, ahora que se comprende mejor la tecnología, esa decisión todavía parece básicamente correcta. Sí, en algunos casos es posible implementar algunos de los contenedores estándar para que se puedan instanciar con tipos incompletos, pero también está claro que en otros casos sería difícil o imposible. Fue principalmente casualidad que la primera prueba que probamos, usando std::vector
, resultó ser uno de los casos fáciles.
Dado que las reglas del lenguaje requieren std::size_t
ser exactas decltype(sizeof(int))
, hacer namespace std { using size_t = decltype(sizeof(int)); }
es una de esas cosas que no rompen nada.
Antes de C ++ 11 no decltype
había forma de declarar el tipo de sizeof
resultado en una declaración simple y, por lo tanto, no existía una buena cantidad de plantillas. size_t
alias diferentes tipos en diferentes arquitecturas de destino, sin embargo, no sería una solución elegante agregar un nuevo tipo integrado solo por el resultado de sizeof
, y no hay typedefs estándar integrados. Por lo tanto, la solución más portátil en ese momento era poner un size_t
alias de tipo en algún encabezado específico y documentarlo.
En C ++ 11 ahora hay una forma de escribir ese requisito exacto del estándar como una simple declaración.