Почему для закрытой структуры, определенной в .h, требуется область видимости в типе .cpp? - PullRequest
0 голосов
/ 13 мая 2019

Заголовок выглядит так:

namespace A {
class A {
  private:
    struct B  {
      int x;
    };

    B foo();
};
}

А мой .cpp выглядит так

namespace A {
   A::B A::foo() { //implement }
}

Почему я не могу просто сделать:

B A::foo() {//implement}

Если B находится внутри A в файле .h, зачем нам нужен A::B в файле cpp? Разве того факта, что мы уже находимся в пространстве имен A, недостаточно, чтобы не определять A::B? Я понимаю, что B является частным для A, но имеет ли это значение в случае пространств имен?

Ответы [ 3 ]

8 голосов
/ 13 мая 2019

Пока вы не достигнете A::foo в определении функции, вы находитесь в области определения функции.Поскольку вы не находитесь в области видимости класса, B не входит в область видимости и приводит к ошибке компилятора.

Вы должны использовать A::, чтобы сообщить компилятору, где находится B.Как только вы достигнете A::foo, вы снова попадаете в область действия A, и это не нужно.Одна вещь, которую вы можете сделать, это использовать конечный тип возвращаемого значения, чтобы поместить возвращаемое значение в область видимости класса, например

auto A::foo() -> B { ... }
0 голосов
/ 13 мая 2019

Если B находится внутри A в файле .h, зачем нам нужен A :: B в файле cpp?

Но B равно , а не ограничено внутри ::A.B находится внутри ::A::A.Таким образом, даже когда вы находитесь в пространстве имен ::A, вам необходимо указать A::B, который находится внутри класса A (полностью определен как ::A::A), поскольку B не объявлен в пространстве имен ::A,Нахождение в пространстве имен ::A означает, что вам не нужно квалифицировать B как A::A::B.

Я понимаю, что B является частным для A, но действительно ли это имеет значение в данном случаепространств имен?

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

0 голосов
/ 13 мая 2019

B является внутренним типом класса A. Когда компилятор встречает B в определении B A::foo() { ... }, он еще не видел A::foo(), чтобы установить, что B следует искать в области действия A, а не как какой-то другой B, который может быть уже в сфере из других. Таким образом, вы должны явно квалифицировать B как A::B на этом этапе определения.

Это не тот случай, если вы вместо этого используете B:

void A::foo(B &b) { ... }

Или как тип возврата для auto возвращаемого значения:

auto A::foo() -> B { ... }

В обоих случаях сначала встречается A::foo(), чтобы установить область, необходимую компилятору для самостоятельного определения, что B относится к A::B.

...