Действительно ли `sizeof` * * оценивает` std:: size_t`? Может это?

Возьмем следующий стандартный проход:

[C++11: 5.3.3/6]: Результат sizeof и sizeof... является константой типа std::size_t. [Примечание: std::size_t определяется в стандартном заголовке <cstddef> (18.2). -end note]

Сейчас:

[C++11: 18.2/6]: Тип size_t представляет собой целочисленный тип без знака, определенный для реализации, который достаточно велик, чтобы содержать размер в байтах любого объекта.

Конечно, в проходе не требуется, чтобы size_t был псевдонимом типа, определенным с помощью typedef, но поскольку он явно заявил, что он доступен стандартным заголовком <cstddef>, я думаю, мы можем считать, что прочитаем, что если не включить <cstddef>, следует удалить любую гарантию, что size_t будет доступным для программы.

Однако, согласно этой первой цитате, мы можем независимо получить выражение типа std::size_t.

Мы можем фактически продемонстрировать оба этих факта:

int main()
{
    typedef decltype(sizeof(0)) my_size_t;

    my_size_t x   = 0;  // OK
    std::size_t y = 1;  // error: 'size_t' is not a member of 'std'
}

std::size_t не отображается программе, но sizeof(0) все еще дает нам один? Действительно?

Нельзя ли сказать, что 5.3.3/6 является ошибочным и что он фактически имеет "тот же тип, что и любой std::size_t разрешается", но не std::size_t сам?

Конечно, эти два являются одинаковыми, если std::size_t является псевдонимом типа, но, опять же, этого не требуется.

Ответ 1

Не путайте карту для территории.

Типы могут быть названы по именам. Эти типы имен могут быть встроены, они могут быть определяемыми пользователем типами, или они могут даже быть параметрами template и ссылаться на несколько разных типов в зависимости от экземпляра.

Но имена не являются типами. Очевидно, что стандарт не предусматривает, что все типы имеют имена - классический struct {} - это тип без имени.

std::size_t - это имя. Он называет тип, возвращаемый sizeof(expression).

У компилятора может быть каноническое имя для типа - __size_t будет одним из способов для него иметь уникальное встроенное каноническое имя типа.

Стандартные гарантии в этом разделе, что независимо от типа sizeof(expression), после #include <cstddef> имя std::size_t теперь относится к этому типу.

В стандарте они относятся к типам по именам. Они не говорят "тип, к которому относится это typename", но просто говорят "тип $NAME $". Компилятор мог решить, что int - это другое имя для __int_32_fast, если оно того захочет, и стандарт тоже не будет возражать.

То же самое происходит с std::nullptr_t и std::initializer_list<Ts> и std::type_info: использование переменных этих типов не всегда требует, чтобы заголовок, который предоставил вам имя для этих типов, включался в вашу программу.

Традиционные встроенные типы C/С++ имели канонические имена, для которых не требовался заголовок. Недостатком является то, что это нарушает существующий код, поскольку новые типы имен в глобальной области взаимодействуют с другими идентификаторами.

Имея "безымянные типы", где вы можете получить имя для них, включая заголовочный файл, мы избегаем этой проблемы.

Ответ 2

Стандарт просто указывает, что тип sizeof(expr) является тем же типом, что и std::size_t. Нет мандата, что использование sizeof(expr) делает доступным имя std::size_t, и поскольку std::size_t просто называет один из встроенных интегральных типов, проблема не возникает.

Ответ 3

Как я понимаю, этот стандартный проход требует следующего выражения:

typeid(sizeof(0)) == typeid(std::size_t)

всегда будет true. Если вы используете фактический идентификатор std::size_t, ::size_t или любой другой псевдоним /typedef будет неактуальным, если сохраняется идентичность типа, как std::typeinfo::operator==().

Проблема с идентичным типом типа появляется в других местах языка. Например, на моей 64-разрядной машине следующий код не может скомпилироваться из-за переопределения функции:

#include <cstddef>
void foo(std::size_t x)
{}

void foo(unsigned long x)
{}

Ответ 4

Да.

Тип, предоставляемый sizeof, представляет собой целое число без знака; реализация определяет, какая из них.

Например, для некоторой конкретной реализации тип выражения sizeof может быть unsigned long.

std::size_t, если он a typedef, является не более чем альтернативным именем для unsigned long. Итак, эти два утверждения:

Тип sizeof ... является константой типа unsigned long

и

Тип sizeof ... является константой типа std::size_t

говорят точно такую ​​же вещь для этой реализации. Тип unsigned long и тип std::size_t являются одним и тем же типом. Разница в том, что последняя является точной для всех (соответствующих) реализаций, где std::size_t может быть псевдонимом для, скажем, unsigned int или другого неподписанного типа.

Что касается компилятора, sizeof дает результат типа unsigned long; компилятор (в отличие от библиотеки времени выполнения) не должен иметь никакого знания имени size_t.

Все это предполагает, что std::size_t (или просто size_t, если вы говорите о C) является typedef. Это не указано ни в C, ни в стандарте С++. Тем не менее, реализация может прямо соответствовать требованиям стандарта, делая size_t typedef. Я не верю, что есть какой-либо другой переносной способ удовлетворить эти требования. (Это не может быть макрос или ключевое слово, определяемое реализацией, поскольку это будет нарушать пространство имен пользователей, а макрос не будет охвачен в пространстве имен std.) Компилятор может сделать size_t конкретную конструкцию, отличную от typedef, но так как typedef работает отлично, нет смысла делать это. Было бы неплохо, ИМХО, если бы в стандарте указано, что size_t является typedef.

(Не имеет значения. Реальная проблема заключается в том, что стандарт ссылается на результат как на "константу". В ISO C "константа" представляет собой токен, такой как целочисленный литерал. С++, насколько я знаю, не определяет существительное "константа", но оно относится к определению термина C. ISO sizeof ... - это константное выражение, оно не является константой. Вызов результата "постоянное значение" был бы разумным. )

Ответ 5

Это тот же тип, но вы должны включить этот заголовок для его использования.