class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Изменить : хотите узнать мотивацию.
class C {
using namespace std; // error
};
namespace N {
using namespace std; // ok
}
int main () {
using namespace std; // ok
}
Изменить : хотите узнать мотивацию.
class/struct
. Это просто не разрешено. Но в принятом ответе обсуждается очень логическое обоснование его запрета. т.е. где рассматривать Hello::World
и где рассматривать World
. Надеюсь, что это развеивает сомнения.
Ответы:
Я не знаю точно, но предполагаю, что разрешение этого на уровне класса может вызвать путаницу:
namespace Hello
{
typedef int World;
}
class Blah
{
using namespace Hello;
public:
World DoSomething();
}
//Should this be just World or Hello::World ?
World Blah::DoSomething()
{
//Is the using namespace valid in here?
}
Поскольку очевидного способа сделать это нет, стандарт просто говорит, что нельзя.
Теперь, когда мы говорим об областях пространства имен, это менее запутанно:
namespace Hello
{
typedef int World;
}
namespace Other
{
using namespace Hello;
World DoSomething();
}
//We are outside of any namespace, so we have to fully qualify everything. Therefore either of these are correct:
//Hello was imported into Other, so everything that was in Hello is also in Other. Therefore this is okay:
Other::World Other::DoSomething()
{
//We're outside of a namespace; obviously the using namespace doesn't apply here.
//EDIT: Apparently I was wrong about that... see comments.
}
//The original type was Hello::World, so this is okay too.
Hello::World Other::DoSomething()
{
//Ditto
}
namespace Other
{
//namespace Hello has been imported into Other, and we are inside Other, so therefore we never need to qualify anything from Hello.
//Therefore this is unambiguiously right
World DoSomething()
{
//We're inside the namespace, obviously the using namespace does apply here.
}
}
using namespace Hello;
внутри других namespace
(и объявление extern
функции внутри него).
Hello::World Blah::DoSomething()
или Blah::World Blah::DoSomething()
(если это разрешено), возвращаемый тип определения функции-члена не считается находящимся в области действия класса на языке, поэтому он должен быть уточнен. Рассмотрим правильный пример замены using
с typedef Hello::World World;
в области видимости класса. Так что никаких сюрпризов быть не должно.
Потому что стандарт C ++ явно запрещает это. Из C ++ 03 §7.3.4 [namespace.udir]:
директива использования : using namespace :: opt спецификатор вложенного имени opt namespace-name ;
С помощью директивы не должна появляться в области видимости класса, но может появиться в области видимости пространства имен или в блоке области. [Примечание: при поиске имени пространства имен в директиве using рассматриваются только имена пространств имен, см. 3.4.6. ]
Почему это запрещено стандартом C ++? Не знаю, спросите члена комитета ISO, который утвердил языковой стандарт.
Я считаю, что причина в том, что это, вероятно, сбивает с толку. В настоящее время при обработке идентификатора уровня класса поиск будет сначала искать в области класса, а затем во включающем пространстве имен. Разрешение using namespace
на уровне класса имело бы некоторые побочные эффекты на то, как теперь выполняется поиск. В частности, это должно было быть выполнено где-то между проверкой этой конкретной области класса и проверкой включающего пространства имен. То есть: 1) объединить уровень класса и поиски на уровне используемого пространства имен, 2) выполнить поиск используемого пространства имен после области действия класса, но перед любой другой областью класса, 3) выполнить поиск используемого пространства имен прямо перед охватывающим пространством имен. 4) поиск объединен с охватывающим пространством имен.
.
namespace A {
void foo() {}
struct B {
struct foo {};
void f() {
foo(); // value initialize a A::B::foo object (current behavior)
}
};
}
struct C {
using namespace A;
struct foo {};
void f() {
foo(); // call A::foo
}
};
.
namespace A {
void foo() {}
}
void bar() {}
struct base {
void foo();
void bar();
};
struct test : base {
using namespace A;
void f() {
foo(); // A::foo()
bar(); // base::bar()
}
};
.
namespace A {
void foo( int ) { std::cout << "int"; }
}
void foo( double ) { std::cout << "double"; }
struct test {
using namespace A;
void f() {
foo( 5.0 ); // would print "int" if A is checked *before* the
// enclosing namespace
}
};
using
объявления на уровне пространства имен. Это не добавит к этому никакого нового значения, но, с другой стороны, усложнит поиск разработчикам компилятора. Поиск идентификатора пространства имен теперь не зависит от того, где в коде запускается поиск. Находясь внутри класса, если поиск не находит идентификатор в области класса, он возвращается к поиску в пространстве имен, но это точно такой же поиск в пространстве имен, который используется в определении функции, нет необходимости поддерживать новое состояние. Когда using
объявление найдено на уровне пространства имен, содержимое используемого пространства имен переносится в это пространство имен для всех поисков, связанных с этим пространством имен. Еслиusing namespace
разрешено на уровне класса, будут разные результаты поиска в одном и том же пространстве имен в зависимости от того, откуда был запущен поиск, и это сделало бы реализацию поиска намного более сложной без дополнительного значения.В любом случае я рекомендую вообще не использовать using namespace
декларацию. Это упрощает понимание кода без необходимости помнить о содержимом всех пространств имен.
using
существуют. Преднамеренно объявляя вещи в глубоко вложенных длинных пространствах имен. Например, glm
делает это и использует несколько уловок для активации / представления функций при использовании клиентом using
.
using namespace std::placeholders
. cf en.cppreference.com/w/cpp/utility/functional/bind
namespace ph = std::placeholders;
Вероятно, это запрещено из-за открытости и закрытости.
Импорт пространств имен в классы приведет к таким забавным случаям:
namespace Foo {}
struct Bar { using namespace Foo; };
namespace Foo {
using Baz = int; // I've just extended `Bar` with a type alias!
void baz(); // I've just extended `Bar` with what looks like a static function!
// etc.
}
namespace Foo
к порядку поиска для всего кода внутри определения типа struct Bar
, что очень похоже на размещение этой строки в теле каждой встроенной функции-члена, за исключением того, что она также будет активна для инициализаторов скобок или равенства и т. Д. Но она все равно будет Срок действия истекает в закрывающей фигурной скобке, как и using namespace
внутри тела функции-члена. Теперь, к сожалению, похоже, нет никакого способа использовать поиск Koenig-with-fallback в инициализаторе фигурных скобок или равных без загрязнения окружающего пространства имен.
Я считаю это дефектом языка. Вы можете использовать обходной путь ниже. Имея в виду этот обходной путь, несложно предложить правила разрешения конфликтов имен для случая, когда язык будет изменен.
namespace Hello
{
typedef int World;
}
// surround the class (where we want to use namespace Hello)
// by auxiliary namespace (but don't use anonymous namespaces in h-files)
namespace Blah_namesp {
using namespace Hello;
class Blah
{
public:
World DoSomething1();
World DoSomething2();
World DoSomething3();
};
World Blah::DoSomething1()
{
}
} // namespace Blah_namesp
// "extract" class from auxiliary namespace
using Blah_namesp::Blah;
Hello::World Blah::DoSomething2()
{
}
auto Blah::DoSomething3() -> World
{
}
using namespace
. C # допускает нечто подобное, но только в области файлов. C ++using namespace
позволяет вам включать одно пространство имен в другое.