Какова область идентификатора пространства имен?

Похоже, что нет четкого определения над точкой декларации, декларативной областью, областью идентификатора пространства имен, кроме тех, что идентификатор внутри пространства имен -according к стандарту (§3.3.6/1).

Декларативная область определения пространства имен - это его пространство имен. Потенциал, обозначенный имя-names-namespace-name - это конкатенация декларативных областей, установленных каждым из namespace-определения в том же...

Хотя стандарт действительно говорит о объявлениях - определение пространства имен - это объявление, которое не применимо к случаю определения пространства имен, поскольку оно не имеет декларатора и не инициализатора - в соответствии со стандартом (§3.3.2/1).

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

Затем, как я могу определить идентификаторы идентификатора пространства имен?

Ответ 1

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

Как вы говорите, пространство имен не может иметь полного декларатора, поскольку для него может быть создан дополнительный декларативный регион для любого модуля компиляции (т.е. исходного файла или заголовка, включенных в этот исходный файл) для любого пространства имен X на namespace X { <new names within this declarative region> }.

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

Это означает, что пространство имен является просто меткой, которая может быть частью идентификатора. istream является идентификатором в пространстве имен std, полное имя этого идентификатора (как указано из кода вне декларативной области пространства имен std) составляет std::istream. Все using namespace std; делает это, пытаясь найти совпадение для потенциального идентификатора foo, говорит компилятору искать в пространстве имен std (или в декларативных областях, где он имеет видимость) для идентификатора с именем foo, который будет кандидатом. [Вот почему using namespace для нескольких пространств имен может привести к двусмысленности, если более одного пространства имен содержит один и тот же идентификатор].

Ответ 2

Исходя из вашего первоначального предположения:

Кажется, что нет четкого определения в точке декларация, декларативный регион, объем идентификатора пространства имен, кроме идентификаторов внутри пространства имен, в соответствии с стандарт (§3.3.6/1).

Я читал это со стандарта, найденного в open-std.org/pdf

3.3.6 Область пространства имен [basic.scope.namespace] 1 Декларативная область определения пространства имен является его пространством имен. Объекты, объявленные в тело пространства имен называется членами пространства имен, а имена введенные этими декларациями в декларативный регион пространство имен называется именами имен пространства имен. Пространство имен имя участника имеет область пространства имен. Его потенциальная сфера включает пространство имен из точки имен декларации (3.3.2) и далее; а также для каждой директивы-распорядителя (7.3.4), которая назначает членов пространства имен, потенциальная область элементов включает в себя часть потенциальная область применения директивы use, которая следует за точкой-членом декларации. [Пример:

namespace N { 
    int i; 
    int g(int a) { return a; } 
    int j(); 
    void q(); 
} 

namespace { int l=1; } 
// the potential scope of l is from its point of declaration 
// to the end of the translation unit 

namespace N { 
    int g(char a) { // overloads N::g(int)
        return l+a; // l is from unnamed namespace 
    } 

    int i; // error: duplicate definition 
    int j(); // OK: duplicate function declaration

    int j() { // OK: definition of N::j() 
        return g(i); // calls N::g(int)
    } 
    int q(); // error: different return type 
} 

-end пример]

Это привело меня к следующим разделам:

3.3

3.3 Сфера охвата [basic.scope] 3.3.1 Декларативные регионы и области видимости [basic.scope.declarative] 1 Каждое имя вводится в некоторой части текста программы, называемой декларативный регион, который является самой большой частью программы, в которой это имя является действительным, то есть, в котором это имя может использоваться как неквалифицированное имя для обозначения одного и того же объекта. В общем, каждый конкретное имя действительно только в некоторых, возможно, несмежных часть текста программы, называемая его областью. Чтобы определить масштаб декларации, иногда удобно ссылаться на потенциал объем декларации. Сфера применения декларации такая же, как и ее потенциальный объем, если потенциальный объем не содержит другого одноименное объявление. В этом случае потенциальный объем декларация во внутреннем (содержащем) декларативном регионе исключается из сферы действия декларации во внешнем (содержащем) декларативный регион. 2 [Пример: в

int j = 24;
int main() {
    int i = j, j;
    j = 42;
}

идентификатор j объявляется дважды как имя (и используется дважды). декларативная область первого j включает весь пример. потенциальная область первого j начинается сразу после этого j и продолжается до конца программы, но ее (фактическая) область исключает текст между и,}. Декларативная область второго объявление j (j непосредственно перед точкой с запятой) включает все текст между {и}, но его потенциальная область исключает декларация i. Область второй декларации j одинакова как его потенциальный охват. -end example] 3 Имена, объявленные декларация вводится в сферу применения декларации происходит, за исключением того, что наличие спецификатора друга (11.3), определенного использования спецификатора разработанного типа (7.1.6.3) и использования-директив (7.3.4) изменить это общее поведение. 4 Учитывая набор деклараций в единый декларативный регион, каждый из которых указывает один и тот же безоговорочное имя, (4.1) - все они относятся к одному и тому же лицу или все относятся к функциям и шаблонам функций; или (4.2) - ровно один декларация объявляет имя класса или имя перечисления, которое не является имя typedef и другие объявления должны относиться к одному и тому же переменная или перечислитель, или все относятся к функциям и функциям шаблоны; в этом случае имя класса или имя перечисления скрыты (3.3.10). [Примечание. Имя пространства имен или имя шаблона класса должно быть уникальным в своем декларативном регионе (7.3.2, п. 14). -end note] § 3.3.1 38

c ISO/IEC N4527 [Примечание. Эти ограничения применяются к декларативному регион, в который вводится имя, что не обязательно так же, как область, в которой происходит объявление. В частности, спецификаторы специфицированных типов (7.1.6.3) и декларации друзей (11.3) может ввести (возможно, не видимое) имя в Пространство имен; эти ограничения распространяются на этот регион. Местный внешний декларации (3.5) могут ввести название в декларативный регион где появляется декларация, а также ввести (возможно, не видимое) в закрытое пространство имен; эти ограничения применяются к оба региона. -end note] 5 [Примечание. Правила поиска имен обобщенное в 3.4. -end note]

3.1

3.1 Объявления и определения [basic.def] 1 Декларация (раздел 7) может вводить одно или несколько имен в единицу перевода или Названия redeclare, введенные предыдущими объявлениями. Если это так, декларация определяет интерпретацию и атрибуты этих имена. Объявление может также иметь последствия, включая: (1.1) - статическую утверждение (п. 7), (1.2) - контроль экземпляра шаблона (14.7.2), (1.3) - использование атрибутов (п. 7) и (1.4) - ничего (в случае пустой декларации). § 3.1 33

c ISO/IEC N4527 2 Объявление является определением, если оно не объявляет функции без указания тела функций (8.4), он содержит спецификатор extern (7.1.1) или спецификация привязки25 (7.5) и ни инициализатор, ни функция, он объявляет статические данные член в определении класса (9.2, 9.4), это имя класса (9.1), это непрозрачная декламация (7.2), это template-parameter (14.1), это параметр-декларация (8.3.5) в Объявление функции, которое не является декларатором определение функции, или это объявление typedef (7.1.3), alias-declaration (7.1.3), использование-декларация (7.3.3), a static_assert-declaration (раздел 7), атрибуция декларации (пункт 7), пустое объявление (раздел 7), директива-использование (7.3.4), явная декларация о создании экземпляра (14.7.2) или явная специализация (14.7.3), декларация которой не является определением. [ Пример: все, кроме одного из следующих, являются определениями:

int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x+a; } // defines f and defines x
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
    int x; // defines non-static data member x
    static int y; // declares static data member y
    X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up, down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX

тогда как это просто объявления:

extern int a; // declares a
extern const int c; // declares c
int f(int); // declares f
struct S; // declares S
typedef int Int; // declares Int
extern X anotherX; // declares anotherX
using N::d; // declares d

-end example] 3 [Примечание: в некоторых случаях реализации С++ неявно определить конструктор по умолчанию (12.1), конструктор копирования (12.8), конструктор перемещения (12.8), оператор присваивания копии (12.8), переместите оператор присваивания (12.8) или деструктор (12.4). -end note] [Пример: данный

#include <string>

struct C {
    std::string s; // std::string is the standard library class (Clause 21)
};

int main() {
    C a;
    C b = a;
    b = a;
}

реализация будет неявно определять функции, чтобы сделать определение C эквивалентно 25). Появляется внутри закрепленного в скобках Объявление-seq в спецификации привязки не влияет на декларация - это определение. § 3.1 34

c ISO/IEC N4527

struct C {
    std::string s;
    C() : s() { }
    C(const C& x): s(x.s) { }
    C(C&& x): s(static_cast<std::string&&>(x.s)) { }
        // : s(std::move(x.s)) { }
    C& operator=(const C& x) { s = x.s; return *this; }
    C& operator=(C&& x) { s = static_cast<std::string&&>(x.s); return *this; }
        // { s = std::move(x.s); return *this; }
    ~C() { }
};

-end example] 4 [Примечание. Имя класса также может быть объявлено неявным образом с помощью спецификатора специфицированного типа (7.1.6.3). -end note] 5 Программа плохо сформированный, если определение любого объекта дает объекту неполный тип (3.9).

Затем вы должны указать:

Хотя стандарт действительно говорит о декларации - namespace-definition - это объявление, которое не применимо к случай определения пространства имен, поскольку он не имеет декларатора, ни инициализатор - согласно стандарту (§3.3.2/1).

Затем я прочитал следующее:

3.3.2 Точка декларации [basic.scope.pdecl] 1 Точка объявления для имени сразу же после его полного декларатора (Пункт 8) и перед его инициализатором (если есть), за исключением случаев, указанных ниже. [Пример:

unsigned char x = 12;
{ unsigned char x = x; }

Здесь второй x инициализируется с его собственным (неопределенным) значением. -end пример]

а затем вы указываете следующее:

Точка объявления для имени сразу после завершения (раздел 8) и перед его инициализатором (если есть), кроме как отмечено ниже...

Наконец я прочитал:

8 Declarators [dcl.decl] 1 Объявление объявляет одну переменную, функции или типа в объявлении. Список инициаторов-деклараторов появляющееся в объявлении, является разделенной запятой последовательностью деклараторы, каждый из которых может иметь инициализатор. init-declarator-list: init-declarator init-declarator-list, init-declarator init-declarator: declarator initializeropt 2 Три компонентами простой декларации являются атрибуты (7.6), спецификаторы (decl-specifier-seq; 7.1) и деклараторы (INIT-описатель-лист). Спецификаторы указывают тип, хранилище класс или другие свойства объявляемых объектов. деклараторы определяют имена этих объектов и (необязательно) изменить тип спецификаторов с помощью таких операторов, как * (указатель to) и() (возврат функции). Исходные значения также могут быть указаны в деклараторе; инициализаторы обсуждаются в 8.5 и 12.6. 3 Каждый init-declarator в декларации анализируется отдельно, как если бы это было в декларации сам по себе .100 4 Деклараторы имеют синтаксис declarator: ptr-declarator noptr-declarator параметры-и-определители tratr-return-type ptr-declarator: noptr-declarator ptr-operator ptr-declarator noptr-declarator: declarator-id parameters-specifier-seqopt noptr-declarator parameters-and-qualifiers noptr-declarator [constant-expressionopt] attribute-specifier-seqopt (ptr-declarator) параметры и квалификаторы: ( параметр-declation-clause) cv-qualifier-seqopt ref-qualifieropt exception-specificationopt attribute-specifier-seqopt 100) A декларация с несколькими деклараторами обычно эквивалентна соответствующая последовательность объявлений, каждая с одним декларатором. Это T D1, D2,... Dn; обычно эквивалентен T D1; T D2;... T Dn; где T - спецификатор decl-specq-seq, и каждый Di является init-декларатором. Исключение возникает, когда имя, введенное одним из деклараторов скрывает имя типа, используемое спецификаторами decl, так что, когда тот же В последующем объявлении используются указатели-декларации, они не имеют то же значение, что и в struct S...; S S, T;//объявляем два экземпляры struct S, которые не эквивалентны структуре S...; S S; S Т; //error Другое исключение возникает, когда T является авто (7.1.6.4), для пример: auto я = 1, j = 2.0;//ошибка: выводимые типы для я и j do не совпадают, в отличие от auto я = 1;//OK: я получил тип int auto j = 2.0;//OK: j выведено, чтобы иметь двойные деклараторы типа 190

c ISO/IEC N4527 trailing-return-type: → trailing-type-specifier-seq abstract-declaratoropt ptr-operator: * attribute-specifier-seqopt cv-qualifier-seqopt и атрибут-спецификатор-seqopt && & && & Атрибут спецификатор-seqopt inested-name-specifier * attribute-specifier-seqopt cv-qualifier-seqopt cv-qualifier-seq: cv-qualifier cv-qualifier-seqopt cv-qualifier: const летучий ref-определитель: && declarator-id:... opt id-expression 5 необязательный атрибут-спецификатор-seq в типах возвращаемого типа возврата к указанному типу возврата. Идентификатор типа в обратном типе возвращаемого типа включает в себя максимально возможную последовательность абстрактных деклараторов. [ Примечание. Это устраняет неоднозначное связывание массива и функции declarators. [Пример: auto f() → int (*) [4];//функция возвращает указатель на массив [4] из int//not function возвращающий массив [4] of указатель на intendend] -end note]

Вы наконец спросите об этом:

Затем, как я могу определить идентификаторы идентификатора пространства имен?

Вы прочитали этот раздел?

7.3 Пространства имен [basic.namespace] 1 Пространство имен является необязательно названным декларативным регионом. Имя пространства имен может использоваться для доступа объекты, объявленные в этом пространстве имен; то есть членов Пространство имен. В отличие от других декларативных регионов, определение пространство имен можно разделить на несколько частей одного или нескольких переводов единицы. 2. Самая внешняя декларативная область единицы перевода - это Пространство имен; см. 3.3.6. 7.3.1 Определение пространства имен [namespace.def] 1 Грамматика для определения пространства имен - namespace-name: идентификатор namespace-alias namespace-definition: named-namespace-definition определение имен в именах-имен-namespace-definition named-namespace-definition: inlineopt namespace Идентификатор атрибута-спецификатора-seqopt {namespace-body} unnamed-namespace-definition: inlineopt namespace attribute-specifier-seqopt {namespace-body} nested-namespace-definition: namespace encing-namespace-specifier:: идентификатор {namespace-body} encoding-namespace-specifier: идентификатор encoding-namespace-specifier:: идентификатор § 7.3.1 168

c ISO/IEC N4527 namespace-body: declaration-seqopt 2 Каждый определение пространства имен должно отображаться в глобальном масштабе или в пространство имен (3.3.6). 3 В определении named-namespace Идентификатор - это имя пространства имен. Если идентификатор, когда (3.4.1), ссылается на имя пространства имен (но не на namespace-alias), введенный в декларативном регионе, в котором named-namespace-definition, определение пространства имен продолжается ранее объявленное пространство имен. В противном случае идентификатор введено как имя пространства имен в декларативный регион, в котором появится имя-namespace-definition. 4 Поскольку namespace-definition содержит декларации в своем пространстве имен и определение пространства имен само по себе является декларацией, из этого следует, что namespace-определения могут быть вложенными. [Пример:

namespace Outer {
    int i;
    namespace Inner {
        void f() { i++; } // Outer::i
        int i;
        void g() { i++; } // Inner::i
    }
}

-end example] 5 Входящими пространствами имен декларации являются те пространства имен в который декларация лексически появляется, за исключением член пространства имен за пределами своего исходного пространства имен (например, определение как указано в 7.3.1.2). Такое переоформление имеет одно и то же namespaces как оригинальное объявление. [Пример:

namespace Q {
    namespace V {
        void f(); // enclosing namespaces are the global namespace, Q, and Q::V
        class C { void m(); };
    }
    void V::f() { // enclosing namespaces are the global namespace, Q, and Q::V
        extern void h(); // ... so this declares Q::V::h
    }
    void V::C::m() { // enclosing namespaces are the global namespace, Q, and Q::V
    }
}

-end example] 6 Если необязательное начальное ключевое слово inline отображается в namespace-definition для определенного пространства имен, это пространство имен объявленный как встроенное пространство имен. Ключевое слово inline можно использовать для определение имен, которое расширяет пространство имен, только если оно было ранее использовавшийся в определении пространства имен, который первоначально был объявлен имя пространства имен для этого пространства имен. 7 Необязательный attribute-specifier-seq в определении namespace namespace пространство имен определено или расширено. 8 Члены встроенного пространство имен может использоваться во многих отношениях, как если бы они были членами охватывающее пространство имен. В частности, встроенное пространство имен и его охватывающее пространство имен добавляются в набор связанных пространств имен используется в зависимом от аргументов поиске (3.4.2), когда один из них есть, и usingdirective (7.3.4), который называет встроенное пространство имен, неявно вставляемое в пространство имен приложений, как для неназванного пространства имен (7.3.1.1). Кроме того, каждый член встроенного пространства имен может впоследствии быть частично специализированным (14.5.5), явно (14.7.2) или явно специализированный (14.7.3), как если бы он были частью охватывающего пространства имен. Наконец, поиск имени в охватывающем пространстве имен через § 7.3.1 169

c Явная квалификация ISO/IEC N4527 (3.4.3.2) будет включать членов встроенного пространства имен, внесенного с помощью директивы using, даже если в объявляемом пространстве имен есть объявления этого имени. 9 Эти свойства являются транзитивными: если пространство имен N содержит встроенный пространство имен M, которое, в свою очередь, содержит встроенное пространство имен O, тогда члены O могут использоваться так, как если бы они были членами M или N. inline namespace set of N является транзитивным замыканием всех встроенных пространства имен в N. Прилагаемый набор пространств имен O представляет собой набор пространства имен, состоящие из самого внутреннего пространства, не входящего в состав встроенного пространства имен встроенное пространство имен O, вместе с любым промежуточным встроенным Пространства имен. 10 Определение вложенного пространства имен с помощью encoding-namespace-specifier E, идентификатор я и пространство-пространство B-пространства имен эквивалентно пространству имен E {пространство имен я {B}} [Пример:

namespace A::B::C {
    int i;
}

Вышеупомянутый эффект имеет тот же эффект, что и:

namespace A {
    namespace B {
        namespace C {
            int i;
        }
    }
}

-end пример]

Я думаю, что важные черты, которые отвечают на ваш вопрос, определяются из его определения 7.3 - 1 и 2 и 7.3.1 - 2,3 и 4. Если вы работаете с именованным пространством имен, и вы уже понимаете область видимости, блок перевода, декларация, определение и декларативное пространство. В объявлении не упоминается декларатор пространства имен, поскольку он указан в разделе декларации в разделе пространства имен, поскольку названное пространство имен или его определение являются его объявлением, поэтому идентификатор является именем самого пространства имен или его определение - декларация.

Ответ 3

Я попытаюсь разбить это на части, основанные на непонимании op.

Он заявил:

Кажется, что нет четкого определения в точке декларация, декларативный регион, объем идентификатора пространства имен

// File A.h
namespace foo {        // Resides At Global Scope
    // some code here.
    void bar();        // Resided At foo:: Scope
}

// File A.cpp
namespace foo {
    // some more code here
    void bar() { 
        std::cout << "Hell World" << std::endl; 
    }
}

Здесь декларативная область охватывает несколько файлов для foo, ее определение и объявление foo, а foo - его идентификатор. Поскольку это именованное пространство имен, нет декларатора, как вы бы видели с переменной, функцией или типом, как определено в разделе 8.1

Декларатор объявляет одну переменную, функцию или тип в пределах Объявление

И нет инициализатора, поскольку это пространство имен. Это декларативный регион с охватом.

И что я считаю, что op спрашивает, так это:

Затем, как я могу определить идентификаторы идентификатора пространства имен?

Идентификатор пространства имен - это имя пространства имен, которое также является его определением и объявлением. В некотором смысле все 3 одно и то же, а декларативная область пространства имен и его область действия одна и та же.

Нет, стандарт не дает четкого представления о точке объявления для пространства имен, поскольку он относится к использованию объявления, которое не имеет пространства имен. В некоторых случаях пространство имен может быть инициализировано другим пространством имен по его определению - декларация как в: Как правило, псевдоним!

namespace someLongName{
}

namespace shortVersion = someLongName {
}

Если точка объявления найдена в 3.3.2.1, Если вы продолжите этот раздел в разделе, он переходит к блоку, области действия прототипа функции, области действия, пространству пространств имен, классу, области перечисления, области параметров шаблона, однако, если вы ссылаетесь на 3.1 в определениях деклараций и определений; пространство имен определено и не объявлено, но в разделе 3.3.6

Декларативная область определения пространства имен является ее Пространство имен тела. Объекты, объявленные в пространстве имен, называются члены пространства имен и имена, введенные этими декларациями в декларативный регион пространства имен называется членом имена пространства имен. Имя члена пространства имен имеет область пространства имен. Его потенциальная сфера включает в себя пространство имен от точки имен декларация (3.3.2); и для каждой использующей-директивы (7.3.4), что назначает пространство имен членов, потенциальную сферу действия членов включает эту часть потенциального объема директивы use который следует за точкой-членом членов.

и

7,3 1 и 2

7.3 Пространства имен [basic.namespace] 1 Пространство имен является необязательно названным декларативным регионом. Имя пространства имен может использоваться для доступа объекты, объявленные в этом пространстве имен; то есть членов Пространство имен. В отличие от других декларативных регионов, определение пространство имен можно разделить на несколько частей одного или нескольких переводов единицы. 2. Самая внешняя декларативная область единицы перевода - это Пространство имен; см. раздел 3.3.6.

и

7.3.1 2-4

2 Каждое определение пространства имен должно отображаться в глобальной области или в пространство имен (3.3.6). 3 В определении named-namespace идентификатор - это имя Пространство имен. Если идентификатор при поиске (3.4.1) относится к namespace-name (но не имя-псевдоним), введенное в декларативный регион, в котором появляется определение named-namespace, определение namespace расширяет ранее объявленное пространство имен. В противном случае идентификатор вводится как имя пространства имен в декларативной области, в которой появляется определение named-namespace. 4 Поскольку определение пространства имен содержит декларации в namespace-body и определение пространства имен - это сама декларация, она следует, что определения пространства имен могут быть вложенными.

Здесь я попытаюсь предложить даже без четкого определения, что точка объявления для пространства имен сразу же после определения идентификатора - объявления!

namespace /*keyword*/ std /*definition, declaration, identifier*/ (point of declaration) { /*beginning of declarative region & scope*/  
    .... // some code

} // End of declarative region or scope until another matching identifier at same level of scope is found. 
  // And this can span multiple translations units.

Надеюсь, это устранит путаницу.