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;
на область обсягу класу at. Тож сюрпризів там бути не повинно.
Оскільки стандарт С ++ це явно забороняє. З C ++ 03 §7.3.4 [namespace.udir]:
директива using : використання простору імен :: opt вкладеного імені-специфікатора opt namespace-name ;
З допомогою директиви не повинна з'являтися в області видимості класу, але може з'явитися в області видимості простору імен або в блоці області. [Примітка: під час пошуку імені простору імен у директиві using враховуються лише імена простору імен, див. 3.4.6. ]
Чому стандарт С ++ це забороняє? Не знаю, запитайте члена комітету 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 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
дозволяє включити один простір імен в інший.