Видимость члена данных класса во вложенном классе?

Насколько мне известно, данные-члены окружающего класса также видны во вложенном классе.

struct A {
    struct B {
        int arr[n];  // how come n is not visible here, but it is visible in next statement.
        int x = n;
    };

    static const int n = 5;
};

смотрите демо здесь

Что ты спрашиваешь?

273K 21.11.2022 07:36

Потому что int x = n; — это полный контекст класса.

Jason Liam 21.11.2022 07:40

Интересный; int arr[A::n]; компилируется с последней версией msvc, но не с gcc.

Ken Y-N 21.11.2022 07:41

@JasonLiam, что это значит? но если мы объявим n перед запуском вложенного класса, он будет работать нормально.

mn_op 21.11.2022 07:44

@ 273K, почему мы не можем объявить arr[n] ?

mn_op 21.11.2022 07:45

@mn_op Если бы вы объявили n перед вложенным классом, поиск имени мог бы найти n, и это работает. Но когда вы объявляете его после вложенного класса, поиск имени не может его найти, а также он не находится в полном контексте класса.

Jason Liam 21.11.2022 07:48

@JasonLiam OP, вероятно, имел в виду: почему n не определено при использовании в определении массива, в то время как оно определено при назначении x. В обоих случаях static const int n = 5; определяется после его вызова.

Rohan Bari 21.11.2022 07:50

@RohanBari int a = n; работает, потому что это полный контекст класса, и стандарт С++ это позволяет. С другой стороны, int arr[n]; не является полным контекстом класса, и стандарт С++ не позволяет этого.

Jason Liam 21.11.2022 07:52

@JasonLiam, когда мы используем полное имя для a, оно работает на msvc. [godbolt.org/z/5MTPTh8Ks] смотрите здесь.

mn_op 21.11.2022 07:53

@mn_op Похоже, это ошибка компилятора.

Jason Liam 21.11.2022 07:54

@mn_op Полный контекст класса (который применяется к инициализатору по умолчанию, но не к типу нестатического члена) означает, что поиск имени выполняется из него, как если бы окончание } класса уже было достигнуто. Так что тогда не имеет значения, как упорядочена декларация n.

user17732522 21.11.2022 07:58

@mn_op Вот отчет об ошибке msvc

Jason Liam 21.11.2022 07:59
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
2
12
90
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

почему n не видно здесь, но видно в следующем утверждении.

Потому что int x = n; — это полный контекст класса, а int arr[n]; — нет. Это можно понять из class.mem, в котором говорится:

6) Полноклассовый контекст класса — это:

6.4) инициализатор члена по умолчанию

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

7) Класс считается полностью определенным типом объекта ([basic.types]) (или полным типом) в конце } спецификатора класса. Класс считается полным в контексте его полного класса; в противном случае он считается неполным в рамках своей собственной спецификации члена класса.

(выделено мной)

Обратите внимание, что n внутри int arr[n]; является частью типа массива, но приведенный выше оператор не позволяет использовать n как часть типа нестатического члена данных и, следовательно, ошибка. По той же причине мы получим ту же ошибку, если напишем:

struct A {
    struct B {
          
        int x = n;
//----------------------v--------->same error as before
        std::array<int, n> arr; 
    };

    static constexpr int n = 5;
};

Цитируемая часть стандарта, по-видимому, объясняет, что такое «контекст полного класса», но не объясняет, почему быть или не быть контекстом полного класса означает n быть видимым или нет в том или ином выражении. Следует также #7 цитировать для полноты картины? В частности, класс считается полным в контексте его полного класса?

Enlico 21.11.2022 08:12

@Enlico Добавил ваше предложение для полноты (каламбур)

Jason Liam 21.11.2022 08:15

@JasonLiam, тогда почему мы можем использовать n как часть типа массива в теле функции-члена? [godbolt.org/z/jGnqEj99e] смотрите демо здесь.

mn_op 21.11.2022 11:45

@mn_op Тело функции также является контекстом полного класса: timsong-cpp.github.io/cppwp/n4861/class.mem#6.1

user17732522 21.11.2022 13:16

Кое-что о переменной оценки в левой части задания, а не эксперте по компьютерному языку, сработало следующее.

#include <iostream>
using namespace std;

    struct A {
        struct B {
            int *arr = new int[n]();
            int x = n;
        };
    
        static const int n = 5;
    };
    int main() {
      cout << "Hello World!";
      return 0;
    }

Это не отвечает на вопрос. ОП не ищет обходного пути.

Jason Liam 21.11.2022 07:52

Мой ответ больше похож на интуицию, почему это так:

В int arr[n] n используется для определения поля, а в int x = n n используется для инициализации поля. Это как B() : x(n) {}.

Подумайте о следующем примере:

struct A {
    struct B {
        int arr[n];
        int x = n;
    };
    static constexpr int n = offsetof(B, x);
};

Здесь значение n зависит от размера arr, а размер обрр зависит от n. Это перекрестная зависимость. Следовательно, struct не совсем точно определен.

Если бы правила С++ были таковы, что ваш вариант использования был бы законным, то это также должно быть законным, чего не может быть. Тем не менее, он по-прежнему позволяет нам использовать offsetof при инициализации, а почему бы и нет?

Другие вопросы по теме