Spec-Zone.ru › C++

Развернутый спецификатор типа

Развернутые спецификаторы типа могут использоваться для ссылки на ранее объявленное имя класса (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) любое количество атрибутов
1) Развернутый спецификатор типа для типа класса.
2) Развернутый спецификатор типа для типа перечисления.
3) Объявление, состоящее только из развернутого спецификатора типа, всегда объявляет тип класса с именем identifier в области видимости, содержащей это объявление.

Неполное объявление перечисления напоминает форму (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 должно использоваться для ссылки на тип перечисления (с областью видимости или без неё)
  • для ссылки на объединение должно использоваться union class-key
  • для ссылки на тип класса, не являющегося объединением, должно использоваться либо class, либо struct class-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 вводится развернутым спецификатором типа.

Ключевые слова

class, struct, union, enum

Ссылки

  • Стандарт 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API