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



class Namespace::Class;


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



namespace Namespace {
class Class;
}


используя VC++ 8.0, компилятор выдает:




ошибка C2653: 'Namespace': это не имя класса или пространства имен




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



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

507   5  

5 ответов:

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

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

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

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

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

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

class Namespace::Class;

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

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

...Хорошо, компилятор. Найти пространство имен Namespace, а внутри это относится к классу с именем Class.

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

namespace Namespace
{
};

class Namespace::Class;

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

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

namespace Namespace
{
    class Class;
};

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

namespace Company::Communications::Sockets {
}

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

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

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

рассматриваемый абзац [class.name]/2:

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

вышеизложенное определяет, что представляет собой прямое объявление (или 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; из действительного прямого объявления, потому что foo::bar не является идентификатором. Это полное имя, что-то другое.

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

namespace Namespace {
  class Class;
}

или

class Namespace {
public:
  class Class;
};

Comments

    Ничего не найдено.