Você poderia fazer sem um cabeçalho:
using size_t = decltype(sizeof(int));
using size_t = decltype(sizeof 1); // The shortest is my favourite.
using size_t = decltype(sizeof "anything");
Isso ocorre porque o padrão C ++ requer:
O resultado de sizeof
e sizeof...
é uma constante do tipo std::size_t
. [Nota: std::size_t
é definido no cabeçalho padrão <cstddef>
(18.2). - nota final]
Em outras palavras, o padrão requer:
static_assert(std::is_same<decltype(sizeof(int)), std::size_t>::value,
"This never fails.");
Observe também que é perfeitamente correto fazer essa typedef
declaração no global e no std
namespace, desde que corresponda a todas as outras typedef
declarações do mesmo nome de typedef (um erro do compilador é emitido em declarações não correspondentes).
Isto é porque:
§7.1.3.1 Um typedef-name não introduz um novo tipo da mesma forma que uma declaração de classe (9.1) ou declaração enum o faz.
§7.1.3.3 Em um determinado escopo de não classe, um typedef
especificador pode ser usado para redefinir o nome de qualquer tipo declarado naquele escopo para se referir ao tipo ao qual ele já se refere.
Para os céticos, dizendo que isso constitui uma adição de um novo tipo ao namespace std
, e tal ato é explicitamente proibido pelo padrão, e isso é UB e isso é tudo; Devo dizer que essa atitude equivale a ignorar e negar uma compreensão mais profunda das questões subjacentes.
O padrão proíbe a adição de novas declarações e definições no namespace std
porque, ao fazer isso, o usuário pode bagunçar a biblioteca padrão e atirar em toda a sua perna. Para os escritores padrão, era mais fácil deixar o usuário se especializar em algumas coisas específicas e banir qualquer outra coisa para uma boa medida, ao invés de banir cada coisa que o usuário não deveria fazer e correr o risco de perder algo importante (e aquela perna). Eles fizeram isso no passado ao exigir que nenhum contêiner padrão seja instanciado com um tipo incompleto, enquanto na verdade alguns contêineres bem poderiam fazer (consulte The Standard Librarian: Containers of Incomplete Types de Matthew H. Austern ):
... No final, tudo parecia muito obscuro e mal compreendido; o comitê de padronização não achou que houvesse outra escolha exceto dizer que os contêineres STL não deveriam funcionar com tipos incompletos. Por precaução, aplicamos essa proibição ao resto da biblioteca padrão também.
... Em retrospecto, agora que a tecnologia foi melhor compreendida, essa decisão ainda parece basicamente correta. Sim, em alguns casos é possível implementar alguns dos contêineres padrão para que eles possam ser instanciados com tipos incompletos - mas também está claro que em outros casos isso seria difícil ou impossível. Foi principalmente por acaso que o primeiro teste que tentamos, usando std::vector
, foi um dos casos fáceis.
Dado que as regras da linguagem exigem std::size_t
ser exatas decltype(sizeof(int))
, fazer namespace std { using size_t = decltype(sizeof(int)); }
é uma daquelas coisas que não quebra nada.
Antes do C ++ 11, não havia decltype
e, portanto, nenhuma maneira de declarar o tipo de sizeof
resultado em uma instrução simples sem envolver uma grande quantidade de modelos. size_t
aliases diferentes tipos em diferentes arquiteturas de destino, no entanto, não seria uma solução elegante adicionar um novo tipo integrado apenas pelo resultado de sizeof
, e não há typedefs integrados padrão. Conseqüentemente, a solução mais portátil na época era colocar size_t
alias de tipo em algum cabeçalho específico e documentá-lo.
No C ++ 11 agora existe uma maneira de escrever esse requisito exato do padrão como uma declaração simples.