Развернутый спецификатор типа
Развернутые спецификаторы типа могут использоваться для ссылки на ранее объявленное имя класса (class, struct или union) или на ранее объявленное имя перечисления, даже если это имя было скрыто объявлением не типа. Их также можно использовать для объявления новых имён классов.
Синтаксис
| class-key class-name | (1) | |
enum enum-name | (2) | |
class-key attr (optional) identifier ; | (3) |
| class-key | - | одно из ключевых слов class, struct, union |
| class-name | - | имя ранее объявленного типа класса, при необходимости квалифицированное, или идентификатор, ранее не объявленный как имя типа |
| enum-name | - | имя ранее объявленного типа перечисления, при необходимости квалифицированное |
| attr | - | (начиная с C++11) любое количество атрибутов |
Неполное объявление перечисления напоминает форму (3), но после неполного объявления перечисления тип перечисления является полным типом.
Пояснение
Форма (3) является особым случаем развернутого спецификатора типа и обычно называется предварительным объявлением класса. Описание формы (3) см. в разделе Предварительное объявление. Далее рассматриваются только формы (1) и (2).
class-name или enum-name в развернутом спецификаторе типа может быть простым идентификатором или квалифицированным идентификатором. Поиск имени выполняется с помощью неквалифицированного поиска имён или квалифицированного поиска имён в зависимости от контекста. Однако в любом случае имена, не являющиеся именами типов, не учитываются.
class T
{
public:
class U;
private:
int U;
};
int main()
{
int T;
T t; // error: the local variable T is found
class T t; // OK: finds ::T, the local variable T is ignored
T::U* u; // error: lookup of T::U finds the private data member
class T::U* u; // OK: the data member is ignored
}
Если поиск имени не находит ранее объявленного имени типа, развернутый спецификатор типа начинается с class, struct или union (то есть не с enum), а class-name является неквалифицированным идентификатором, то развернутый спецификатор типа представляет собой объявление класса с именем class-name, а целевой областью видимости является ближайшая внешняя область видимости пространства имён или блока.
template<typename T>
struct Node
{
struct Node* Next; // OK: lookup of Node finds the injected-class-name
struct Data* Data; // OK: declares type Data at global scope
// and also declares the data member Data
friend class ::List; // error: cannot introduce a qualified name
enum Kind* kind; // error: cannot introduce an enum
};
Data* p; // OK: struct Data has been declared
Если имя ссылается на имя typedef, псевдоним типа, параметр шаблона типа или специализацию шаблона-псевдонима, программа некорректна. В противном случае развернутый спецификатор типа вводит имя в объявление так же, как простой спецификатор типа вводит имя типа.
template<typename T>
class Node
{
friend class T; // error: type parameter cannot appear in an elaborated type specifier;
// note that similar declaration `friend T;` is OK.
};
class A {};
enum b { f, t };
int main()
{
class A a; // OK: equivalent to 'A a;'
enum b flag; // OK: equivalent to 'b flag;'
}
Ключевое слово class-key или enum, присутствующее в развернутом спецификаторе типа, должно соответствовать по виду объявлению, на которое ссылается имя в развернутом спецификаторе типа.
- ключевое слово
enumдолжно использоваться для ссылки на тип перечисления (с областью видимости или без неё) - для ссылки на объединение должно использоваться
unionclass-key - для ссылки на тип класса, не являющегося объединением, должно использоваться либо
class, либоstructclass-key (ключевые словаclassиstructздесь взаимозаменяемы).
enum class E { a, b };
enum E x = E::a; // OK
enum class E y = E::b; // error: 'enum class' cannot introduce an elaborated type specifier
struct A {};
class A a; // OK
При использовании в качестве аргумента шаблона class T является параметром шаблона типа с именем T, а не безымянным параметром, не являющимся типом, тип которого T вводится развернутым спецификатором типа.
Ключевые слова
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
- 6.5.6 Развернутые спецификаторы типа [basic.lookup.elab]
- 9.2.9.4 Развернутые спецификаторы типа [dcl.type.elab]
- Стандарт C++20 (ISO/IEC 14882:2020):
- 6.5.4 Развернутые спецификаторы типа [basic.lookup.elab]
- 9.2.8.3 Развернутые спецификаторы типа [dcl.type.elab]
- Стандарт C++17 (ISO/IEC 14882:2017):
- 6.4.4 Развернутые спецификаторы типа [basic.lookup.elab]
- 10.1.7.3 Развернутые спецификаторы типа [dcl.type.elab]
- Стандарт C++14 (ISO/IEC 14882:2014):
- 3.4.4 Развернутые спецификаторы типа [basic.lookup.elab]
- 7.1.6.3 Развернутые спецификаторы типа [dcl.type.elab]
- Стандарт C++11 (ISO/IEC 14882:2011):
- 3.4.4 Развернутые спецификаторы типа [basic.lookup.elab]
- 7.1.6.3 Развернутые спецификаторы типа [dcl.type.elab]
- Стандарт C++98 (ISO/IEC 14882:1998):
- 3.4.4 Развернутые спецификаторы типа [basic.lookup.elab]
- 7.1.5.3 Развернутые спецификаторы типа [dcl.type.elab]
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/elaborated_type_specifier