Почему я не могу использовать функции foo :: bar внутри sub :: bar при использовании пространства имен foo? - PullRequest
0 голосов
/ 15 февраля 2019

Рассмотрим следующую программу:

namespace foo {
namespace sub {
int f();
} // namespace sub 
} // namespace foo 

namespace bar {
namespace sub {

int g()  {
    using namespace foo;
    return sub::f() + 1;
}

} // namespace sub 
} // namespace bar 

Я ожидаю, что это скомпилируется, но - это не так:

$ g++-6 -c a.cpp
a.cpp: In function ‘int bar::sub::g()’:
a.cpp:12:9: error: ‘f’ is not a member of ‘bar::sub’
  return sub::f() + 1;
         ^~~
a.cpp:12:9: note: suggested alternative:
a.cpp:3:5: note:   ‘foo::sub::f’
 int f();
     ^

тоже не повезло с клангом:

$ clang++-6.0 -c a.cpp
a.cpp:12:9: error: no member named 'f' in namespace 'bar::sub'; did you mean 'foo::sub::f'?
        return sub::f() + 1; 
               ^~~~~~
               foo::sub::f
a.cpp:3:5: note: 'foo::sub::f' declared here
int f();
    ^
1 error generated.

и он знает , какую функцию я тоже хочу!

Теперь я понимаю, что все могло бы быть неоднозначным, если бы здесь были и foo::sub::f, и bar::sub::f.Но - почему bar::sub «прячется» foo::sub, даже когда я явно прошу использовать foo::sub функции?

Чтобы было ясно, что может дать ответ:

  • Anобъяснение, почему это (наиболее) разумное поведение, и мои ожидания неоправданны.
  • Обоснование этого заключается в стандарте C ++.
  • Цитата из стандарта говорит, что это должно бытьдело;возможно, контекст поможет мне понять, почему это было решено.

Мотивация: я написал свой код так, чтобы последнее пространство имен перед функцией было частью имени метода, в том смысле, чтоне понимаю, что делает функция, не добавляя пространство имен.Поэтому вместо того, чтобы говорить sub_f(), как я бы сказал в C, я хочу иметь возможность сказать sub::f().Это оказывается трудным сделать без указания более длинного пути пространств имен.

Ответы [ 3 ]

0 голосов
/ 15 февраля 2019

[namespace.udir] говорит (выделено мое):

-2- using-директива указывает, что имена в номинированном пространстве имен могут использоваться в области действияв котором директива использования появляется после директивы использования . Во время поиска безоговорочного имени (6.4.1) имена появляются так, как если бы они были объявлены в ближайшем окружающем пространстве имен, которое содержит как using-директиву , так и номинированное пространство имен. [Примечание: В этом контексте «содержит» означает «содержит прямо или косвенно». - примечание к концу]

В вашем примере "имена в номинированном пространстве имен" просто foo::sub, потому что это единственное имя, объявленное в пространстве имен foo, и "Ближайшее окружающее пространство имен, которое содержит директиву using и назначенное пространство имен ", является глобальным пространством имен.Таким образом, foo::sub выглядит (для целей поиска по имени), как если бы оно было в глобальном пространстве имен, например:

namespace sub {
int f();
} // namespace sub 

namespace bar {
namespace sub {

int g()  {
    return sub::f() + 1;
}

} // namespace sub 
} // namespace bar 

Теперь должно быть более очевидно, что sub::f ничего не найдет.Поиск имени для sub::f начинается с поиска sub.Он не находит его в окружающем пространстве имен (которое bar::sub), поэтому он смотрит в следующую внутреннюю включающую область (который bar) и там находит sub.В этот момент поиск имени для sub останавливается, он не ищет в глобальном пространстве имен, где он обнаружил бы foo::sub, видимый директивой using .

Следующий шаг поиска имени пытается найти f в области, которую он нашел для sub, но в найденном им пространстве имен f нет, поэтому поиск по имени не удался.

* 1045Директивы using не работают как добавление объявления использования для каждого члена пространства имен, они "более слабые", чем объявления использования.Причина этого заключается в том, что имена, действительно объявленные в пространстве имен, имеют приоритет над именами, которые просто становятся видимыми с помощью директивы using. ответ Родриго на связанный вопрос объясняет это более подробно.
0 голосов
/ 15 февраля 2019

Ответ на ваш первый пункт:
Что происходит, когда вы добавляете в свою программу a:

namespace sub
{
    int f();
}

Что теперь должен выбрать компилятор: :: sub :: f () или (используя:: foo: :) sub :: f ()?

0 голосов
/ 15 февраля 2019

Я думаю, что соответствующая часть стандарта, которая препятствует тому, что вы пытаетесь сделать, такова:

6.3.10 Сокрытие имени [basic.scope.hiding]
...
4 При поиске имени, квалифицированного именем пространства имен, объявления , которые в противном случае были бы сделаны видимыми с помощью директивы using, могут быть скрыты объявлениями с таким жеимя в пространстве имен, содержащее директиву using ;

У вас есть sub в пространствах имен foo и barsub в bar скрывает sub в foo, несмотря на директиву using.И именно поэтому f() в foo::sub также не видны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...