Type
Объекты , ссылки , функции , включая специализации шаблонов функций , и выражения обладают свойством, называемым тип , которое ограничивает операции, разрешенные для этих сущностей, и придает семантическое значение иначе общим последовательностям битов.
Содержание |
Классификация типов
Система типов C++ состоит из следующих типов:
- фундаментальные типы (см. также std::is_fundamental ):
-
- тип void (см. также std::is_void );
|
(начиная с C++11) |
-
- арифметические типы (см. также std::is_arithmetic ):
-
- целочисленные типы (включая cv-квалифицированные версии , см. также std::is_integral , синонимом целочисленного типа является тип integer):
-
- тип bool ;
- символьные типы:
-
- типы узких символов:
-
- обычные символьные типы: char , signed char , unsigned char [1]
|
(начиная с C++20) |
-
-
-
-
- типы широких символов: char16_t , char32_t , (начиная с C++11) wchar_t ;
- знаковые целочисленные типы:
-
- стандартные знаковые целочисленные типы: signed char , short , int , long , long long ;
-
-
-
|
(since C++11) |
-
-
-
- беззнаковые целочисленные типы:
-
- стандартные беззнаковые целочисленные типы: unsigned char , unsigned short , unsigned , unsigned long , unsigned long long ;
-
-
|
(since C++11) |
-
-
- типы с плавающей запятой (см. также std::is_floating_point ):
-
- стандартные типы с плавающей запятой: float , double , long double и их cv-квалифицированные версии ;
-
|
(since C++23) |
- составные типы (см. также std::is_compound ):
-
- типы ссылок (см. также std::is_reference ):
-
- типы lvalue-ссылок (см. также std::is_lvalue_reference ):
-
- lvalue-ссылки на объектные типы;
- lvalue-ссылки на функциональные типы;
|
(начиная с C++11) |
-
- pointer types (см. также std::is_pointer ):
- pointer-to-member types (см. также std::is_member_pointer ):
-
- pointer-to-data-member types (см. также std::is_member_object_pointer );
- pointer-to-member-function types (см. также std::is_member_function_pointer );
- array types (см. также std::is_array );
- function types (см. также std::is_function );
- enumeration types (см. также std::is_enum );
|
(начиная с C++11) |
-
-
- необъединённые типы (см. также std::is_class );
- union types (см. также std::is_union ).
-
- ↑ signed char и unsigned char являются типами узких символов, но они не являются символьными типами. Другими словами, множество типов узких символов не является подмножеством множества символьных типов.
Для каждого неквалифицированного по cv типа, кроме ссылки и функции, система типов поддерживает три дополнительные cv-квалифицированные версии этого типа ( const , volatile и const volatile ).
Другие категории
Тип объекта (см. также std::is_object ) — это (возможно, cv-квалифицированный) тип, который не является типом функции, не является ссылочным типом и не является (возможно, cv-квалифицированным) void .
Следующие типы в совокупности называются скалярными типами (см. также std::is_scalar ):
- арифметические типы
- типы перечислений
- типы указателей
- типы указателей на члены
| (начиная с C++11) |
- cv-квалифицированные версии этих типов
Следующие типы в совокупности называются типами с неявным временем жизни :
- скалярные типы
- классы неявного времени жизни
- массивы
- cv-квалифицированные версии этих типов
|
Следующие типы в совокупности называются тривиально копируемыми типами :
Следующие типы в совокупности называются типами со стандартным размещением :
|
(начиная с C++11) |
| Диаграмма иерархии type traits |
|---|
|
Примечание: элементы SVG-изображения кликабельны, но сначала необходимо открыть диаграмму в новой вкладке браузера |
Устаревшие категории
|
Следующие типы в совокупности называются POD типами (см. также std::is_pod ):
|
(устарело в C++20) |
|
Следующие типы в совокупности называются тривиальными типами (см. также std::is_trivial ):
|
(начиная с C++11)
(устареет в C++26) |
Пользовательский тип данных
Программно-определенная специализация — это явная специализация или частичная специализация , которая не является частью стандартной библиотеки C++ и не определена реализацией.
A program-defined type — это один из следующих типов:
- A non- closure (since C++11) class type или enumeration type который не является частью стандартной библиотеки C++ и не определён реализацией.
|
(since C++11) |
- Создание экземпляра специализации, определённой в программе.
Наименование типов
Имя name может быть объявлено для ссылки на тип с помощью:
- class объявление;
- union объявление;
- enum объявление;
- typedef объявление;
- type alias объявление.
Типы, которые не имеют имён, часто требуют упоминания в программах на C++; синтаксис для этого известен как
type-id
. Синтаксис type-id, который именует тип
T
, в точности соответствует синтаксису
объявления
переменной или функции типа
T
, с опущенным идентификатором, за исключением того, что
decl-specifier-seq
грамматики объявления ограничивается
type-specifier-seq
, и что новые типы могут быть определены только если type-id появляется в правой части объявления псевдонима нетemplate-типа.
int* p; // объявление указателя на int static_cast<int*>(p); // type-id это "int*" int a[3]; // объявление массива из 3 int new int[3]; // type-id это "int[3]" (называется new-type-id) int (*(*x[2])())[3]; // объявление массива из 2 указателей на функции // возвращающих указатель на массив из 3 int new (int (*(*[2])())[3]); // type-id это "int (*(*[2])())[3]" void f(int); // объявление функции принимающей int и возвращающей void std::function<void(int)> x = f; // параметр шаблона типа это type-id "void(int)" std::function<auto(int) -> void> y = f; // то же самое std::vector<int> v; // объявление вектора int sizeof(std::vector<int>); // type-id это "std::vector<int>" struct { int x; } b; // создает новый тип и объявляет объект b этого типа sizeof(struct { int x; }); // ошибка: нельзя определять новые типы в выражении sizeof using t = struct { int x; }; // создает новый тип и объявляет t как псевдоним этого типа sizeof(static int); // ошибка: спецификаторы класса хранения не являются частью type-specifier-seq std::function<inline void(int)> f; // ошибка: спецификаторы функций также не допускаются
Часть грамматики объявления декларатора с удаленным именем называется абстрактным декларатором .
Type-id может использоваться в следующих ситуациях:
- для указания целевого типа в выражениях приведения ;
-
в качестве аргументов для
sizeof,alignof,alignas,new, иtypeid; - в правой части объявления псевдонима типа ;
- в качестве завершающего возвращаемого типа в объявлении функции ;
- в качестве аргумента по умолчанию для шаблонного параметра типа ;
- в качестве шаблонного аргумента для шаблонного параметра типа ;
| (до C++17) |
Type-id может использоваться с некоторыми модификациями в следующих ситуациях:
- в списке параметров функции (когда имя параметра опущено), type-id использует decl-specifier-seq вместо type-specifier-seq (в частности, разрешены некоторые спецификаторы класса памяти);
- в имени пользовательской функции преобразования , абстрактный декларатор не может включать операторы функции или массива.
|
Этот раздел не завершён
Причина: 8.2[dcl.ambig.res] если это может быть компактно изложено |
|
Этот раздел не завершён
Причина: упомянуть и дать ссылки на decltype и auto |
Уточняющий спецификатор типа
Уточненные спецификаторы типа могут использоваться для ссылки на ранее объявленное имя класса (class, struct или union) или на ранее объявленное имя перечисления, даже если имя было скрыто объявлением не-типа . Они также могут использоваться для объявления новых имен классов.
См. elaborated type specifier для получения подробной информации.
Статический тип
Тип выражения, который определяется в результате анализа программы на этапе компиляции, называется статическим типом выражения. Статический тип не изменяется во время выполнения программы.
Динамический тип
Если некоторое glvalue выражение ссылается на полиморфный объект , тип его наиболее производного объекта называется динамическим типом.
// дано struct B { virtual ~B() {} }; // полиморфный тип struct D : B {}; // полиморфный тип D d; // самый производный объект B* ptr = &d; // статический тип (*ptr) - B // динамический тип (*ptr) - D
Для выражений prvalue динамический тип всегда совпадает со статическим типом.
Неполный тип
Следующие типы являются неполными типами :
- тип void (возможно cv -квалифицированный);
-
неполные типы объектов
:
- тип класса, который был объявлен (например, с помощью forward declaration ), но не определен;
- array of unknown bound ;
- массив элементов неполного типа;
- enumeration type от точки объявления до определения его базового типа.
Все остальные типы являются полными.
Любой из следующих контекстов требует, чтобы тип
T
был полным:
-
определение
или вызов функции с возвращаемым типом
Tили типом аргументаT; -
определение
объекта типа
T; -
объявление
нестатического члена класса
типа
T; -
newвыражение для объекта типаTили массива с типом элементовT; -
преобразование lvalue в rvalue
, примененное к glvalue типа
T; -
неявное
преобразование
или
явное
преобразование в тип
T; -
стандартное
преобразование
,
dynamic_cast, илиstatic_castв тип T * или T & , за исключением преобразования из нулевого указателя или из указателя на возможно cv-квалифицированный void ; -
оператор доступа к члену класса
, примененный к выражению типа
T; -
typeid,sizeof, илиalignofоператор, примененный к типуT; -
арифметический оператор
, примененный к указателю на
T; -
определение класса с базовым классом
T; -
присваивание lvalue типа
T; -
обработчик
исключения
типа
T, T & , или T * .
(В общем случае, когда размер и расположение
T
должны быть известны.)
Если любая из этих ситуаций возникает в единице трансляции, определение типа должно присутствовать в той же единице трансляции. В противном случае это не требуется.
Не полностью определённый тип объекта может быть завершён:
- Тип класса (такой как class X ) может считаться неполным в одной точке единицы трансляции и считаться полным позже; тип class X является одним и тем же типом в обеих точках:
struct X; // объявление X, определение пока не предоставлено extern X* xp; // xp - указатель на неполный тип: // определение X недоступно void foo() { xp++; // некорректно: X неполный } struct X { int i; }; // определение X X x; // OK: определение X доступно void bar() { xp = &x; // OK: тип "указатель на X" xp++; // OK: X полный }
- Объявленный тип массива может быть массивом незавершенного типа класса и, следовательно, незавершенным; если тип класса завершается позже в единице трансляции, тип массива становится завершенным; тип массива в этих двух точках является одним и тем же типом.
-
Объявленный тип массива может быть массивом неизвестной границы и, следовательно, быть незавершенным в одной точке единицы трансляции и завершенным позже; типы массивов в этих двух точках ("массив неизвестной границы
T" и "массив NT") являются разными типами.
Тип указателя или ссылки на массив неизвестной границы постоянно указывает на или ссылается на неполный тип. Массив неизвестной границы, именованный через
typedef
объявление, постоянно ссылается на неполный тип. В любом из случаев тип массива не может быть завершён:
extern int arr[]; // тип arr является неполным typedef int UNKA[]; // UNKA является неполным типом UNKA* arrp; // arrp - указатель на неполный тип UNKA** arrpp; void foo() { arrp++; // ошибка: UNKA является неполным типом arrpp++; // OK: размер UNKA* известен } int arr[10]; // теперь тип arr является полным void bar() { arrp = &arr; // OK: квалификационное преобразование (начиная с C++20) arrp++; // ошибка: UNKA не может быть завершен }
Отчеты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение в опубликованной версии | Корректное поведение |
|---|---|---|---|
| CWG 328 | C++98 |
члены класса неполного типа не запрещались
если объект типа класса никогда не создавался |
нестатические члены данных класса
должны быть полными |
| CWG 977 | C++98 |
момент, когда тип перечисления становится
полным в его определении, был неясен |
тип становится полным после
определения базового типа |
| CWG 1362 | C++98 |
пользовательские преобразования в тип
T*
или
T&
требовали
T
быть полным
|
не требуется |
| CWG 2006 | C++98 | cv-квалифицированные void типы были типами объектов и полными типами | исключены из обеих категорий |
| CWG 2448 | C++98 | только cv-неквалифицированные типы могли быть целочисленными и типами с плавающей точкой | разрешает cv-квалифицированные типы |
| CWG 2630 | C++98 |
было неясно, считается ли класс полным вне
единицы трансляции, где появляется определение класса |
класс считается полным
если его определение достижимо в этом случае |
| CWG 2643 | C++98 |
тип указателя на массив неизвестной границы
не мог быть завершен (но он уже полный) |
тип массива, на который указывают,
не может быть завершен |
| LWG 2139 | C++98 | значение термина "пользовательский тип" было неясно |
определяет и использует "программно-
определенный тип" вместо этого |
| LWG 3119 | C++11 | было неясно, являются ли типы замыканий программно-определенными типами | прояснено |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
-
- 6.8.2 Фундаментальные типы [basic.fundamental]
- Стандарт C++20 (ISO/IEC 14882:2020):
-
- 6.8.2 Фундаментальные типы [basic.fundamental]
- Стандарт C++17 (ISO/IEC 14882:2017):
-
- 6.9.1 Фундаментальные типы [basic.fundamental]
- Стандарт C++14 (ISO/IEC 14882:2014):
-
- 3.9.1 Фундаментальные типы [basic.fundamental]
- Стандарт C++11 (ISO/IEC 14882:2011):
-
- 3.9.1 Фундаментальные типы [basic.fundamental]
- Стандарт C++98 (ISO/IEC 14882:1998):
-
- 3.9.1 Фундаментальные типы [basic.fundamental]
Смотрите также
| Type traits | Интерфейсы на основе шаблонов времени компиляции для запроса свойств типов |
|
C documentation
для
Type
|
|
Внешние ссылки
| 1. | Дерево типов C++0x от Howard Hinnant |