Почему я не могу переадресовать класс объявления в пространстве имен, используя двойные двоеточия?

class Namespace::Class;

Зачем мне это нужно?:

namespace Namespace {
    class Class;
}

Используя VС++ 8.0, проблемы компилятора:

ошибка C2653: "Пространство имен": не является именем класса или пространства имен

Я предполагаю, что проблема здесь в том, что компилятор не может определить, является ли Namespace классом или пространством имен? Но почему это имеет значение, поскольку это просто декларация?

Есть ли другой способ переслать-объявить класс, определенный в каком-либо пространстве имен? Синтаксис выше кажется, что я "повторно открываю" пространство имен и расширяю его определение. Что делать, если Class на самом деле не определено в Namespace? Это приведет к ошибке в какой-то момент?

Ответ 1

Потому что вы не можете. На языках С++ полностью квалифицированные имена используются только для обозначения существующих (т.е. Ранее объявленных) объектов. Они не могут использоваться для введения новых объектов.

И вы фактически "открываете" пространство имен для объявления новых объектов. Если класс Class позже определяется как член другого пространства имен - это совершенно другой класс, который не имеет ничего общего с тем, который вы заявили здесь.

Как только вы дойдете до определения заранее объявленного класса, вам больше не нужно "повторно открывать" пространство имен. Вы можете определить его в глобальном пространстве имен (или в любом пространстве имен, охватывающем ваш Namespace), как

class Namespace::Class {
  /* whatever */
};

Поскольку вы ссылаетесь на объект, который уже был объявлен в пространстве имен Namespace, вы можете использовать квалифицированное имя Namespace::Class.

Ответ 2

Вы получаете правильные ответы, позвольте мне просто повторить формулировку:

class Namespace::Class;

Почему я должен это делать?

Вы должны сделать это, потому что термин Namespace::Class сообщает компилятору:

... ОК, компилятор. Найдите пространство имен с именем Namespace и внутри которые относятся к классу Class.

Но компилятор не знает, о чем вы говорите, потому что он не знает пространства имен с именем Namespace. Даже если бы существовало пространство имен с именем Namespace, как в:

namespace Namespace
{
};

class Namespace::Class;

он все равно не будет работать, потому что вы не можете объявить класс в пространстве имен вне этого пространства имен. Вы должны находиться в пространстве имен.

Таким образом, на самом деле вы можете объявить класс в пространстве имен. Просто сделайте следующее:

namespace Namespace
{
    class Class;
};

Ответ 3

Я полагаю, что по той же причине вы не можете объявить вложенные пространства имен в один ход следующим образом:

namespace Company::Communications::Sockets {
}

и вы должны сделать это:

namespace Company {
  namespace Communications {
    namespace Sockets {
    }
  }
}

Ответ 4

Здесь есть много отличных ответов на вопрос о том, что было причиной отказа от него. Я просто хочу предоставить скучную стандартную статью, которая специально запрещает ее. Это справедливо для С++ 17 (n4659).

Этот параграф [class.name]/2:

Объявление, состоящее исключительно из идентификатора ключа класса; является либо переоформление имени в текущем поле или вперед объявление идентификатора в качестве имени класса. Он вводит класс name в текущую область.

Приведенное выше определяет, что представляет собой форвардное объявление (или redclaration класса). По существу, он должен быть одним из class identifier;, struct identifier; или union identifier;, где идентификатор является общим лексическим определением в [lex.name]:

identifier:
  identifier-nondigit
  identifier identifier-nondigit
  identifier digit
identifier-nondigit:
  nondigit
  universal-character-name
nondigit: one of
  a b c d e f g h i j k l m
  n o p q r s t u v w x y z
  A B C D E F G H I J K L M
  N O P Q R S T U V W X Y Z _
digit: one of
  0 1 2 3 4 5 6 7 8 9

Что представляет собой создание общей схемы [a-zA-Z_][a-zA-Z0-9_]*, с которой мы все знакомы. Как вы можете видеть, это исключает class foo::bar; из действительного объявления forward, потому что foo::bar не является идентификатором. Это полное имя, что-то другое.