Языковые юристы, внимание!

У меня есть такой код:

namespace conflicting 
{
    struct Foo {};
}

namespace outer
{
    namespace conflicting
    {
        struct Bar {};
    }
}

using namespace outer;

int main()
{
    conflicting::Bar b;
    return 0;
} 

Используя g ++ 4.8.2, я получаю следующие ошибки при попытке компиляции:

t.cpp: In function ‘int main()’:
t.cpp:18:5: error: reference to ‘conflicting’ is ambiguous
     conflicting::Bar b;
     ^
t.cpp:2:1: note: candidates are: namespace conflicting { }
 {
 ^
t.cpp:9:5: note:                 namespace outer::conflicting { }
     {
     ^
t.cpp:18:5: error: reference to ‘conflicting’ is ambiguous
     conflicting::Bar b;
     ^
t.cpp:2:1: note: candidates are: namespace conflicting { }
 {
 ^
t.cpp:9:5: note:                 namespace outer::conflicting { }
     {
     ^
t.cpp:18:22: error: expected ‘;’ before ‘b’
     conflicting::Bar b;

Может ли кто-нибудь объяснить мне, почему возникает эта ошибка (возможно, обратитесь к разделу стандарта)?

c++
1
Slartibartfast 19 Фев 2016 в 20:32

3 ответа

Лучший ответ

Краткое резюме: для того, чтобы X :: m был квалифицированным идентификатором, X должен однозначно ссылаться на одно пространство имен.

conflicting::Bar - это квалифицированный идентификатор, если conflicting - это «вложенный спецификатор имени, который называет пространство имен», а Bar - имя члена этого пространства имен (или имя член пространства имен, видимый с помощью директивы using) "(все ссылки относятся к N3337, и все внимание мое):

5.1.1 Общие [expr.prim.general]

  1. A :: или спецификатор вложенного имени, который именует пространство имен (7.3), в любом случае за которым следует t имя члена этого пространства имен (или имя члена пространства имен, сделанного видимым с помощью директивы using) является квалифицированным идентификатором; 3.4.3.2 описывает поиск по именам для членов пространства имен, которые появляются в квалифицированных идентификаторах. Результат является членом. Тип результата - это тип члена. Результатом является lvalue, если член является функцией или переменной, и prvalue в противном случае.

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

3.4 Поиск имени [basic.lookup]

  1. Правила поиска по именам применяются единообразно ко всем именам (включая имена-typedef (7.1.3), имена-пространств имен (7.3) и имена-классов (9.1)) везде, где грамматика допускает такие имена в контексте, обсуждаемом определенным правилом. Поиск имени связывает использование имени с объявлением (3.1) этого имени. Поиск имени должен найти однозначное объявление для имени (см. 10.2). Поиск имени может связать более одного объявления с именем, если он обнаруживает, что имя является именем функции; говорят, что объявления образуют набор перегруженных функций (13.1). Разрешение перегрузки (13.3) происходит после успешного поиска имени. Правила доступа (раздел 11) рассматриваются только после успешного поиска имени и разрешения перегрузки функции (если применимо). Только после успешного поиска имени, разрешения перегрузки функции (если применимо) и проверки доступа атрибуты, введенные объявлением имени, используются далее при обработке выражений (раздел 5).

Формулировка Раздела 3.4.3.2 проясняет, что пространство имен должно быть уникальным:

3.4.3.2 Члены пространства имен [namespace.qual]

  1. Для пространства имен X и имени m поисковый набор S (X, m) с указанием пространства имен определяется следующим образом: Пусть S '(X, m) будет набором всех объявлений m в X и встроенным набором пространств имен X (7.3.1). Если S '(X, m) не пусто, S (X, m) есть S' (X, m); в противном случае S (X, m) является объединением S (N_i, m) для всех пространств имен Ni, назначенных директивами using в X и его встроенном наборе пространств имен.

Это описание предполагает, что X уникален, поскольку оно не описывает какой-либо процесс для итерации по набору возможных пространств имен для нахождения m.

Поскольку компилятор не может определить, какое пространство имен conflicting использовать в качестве отправной точки для поиска члена пространства имен, он выдает ошибку.

Надеюсь, это поможет.

0
godel9 19 Фев 2016 в 18:16

Вам не нужен для этого языковой юрист! Как только вы ввели пространство имен outer в свое текущее пространство имен (с помощью using его), все его имена стали видимыми. Итак, теперь у вас конфликт.

Вот почему я категорически не рекомендую использовать пространство имен using. Пространства имен были изобретены не просто так, и причина состоит в том, чтобы предотвратить такие проблемы.

-1
SergeyA 19 Фев 2016 в 17:34

Вы уточнили имя с помощью conflicting::, поэтому компилятору нужно искать Bar в этой области ... но в какой области? Он может относиться к двум разным, ::conflicting или outer::conflicting, на которые можно ссылаться без префикса outer:: из-за директивы using.

1
Jonathan Wakely 19 Фев 2016 в 17:35