Почему использование директивы ведет себя по-разному в глобальном масштабе и в локальной области?

Когда я пишу следующий код, он скомпилируется и выполняется правильно:

#include <iostream>
using namespace std;

namespace first
{
  int x = 5;
  int y = 10;
}

namespace second
{
  double x = 3.1416;
  double y = 2.7183;
}

int main () {
  using namespace first; //using derective
  using second::y;
  cout << x << endl;
  cout << y << endl;
  return 0;
}

Но если я пишу, используя директивы вне основной функции, следующим образом,

using namespace first; //using derective
using second::y;
int main () {
  cout << x << endl;
  cout << y << endl;
  return 0;
}

Он дает эту ошибку компиляции:

g++     namespace03.cpp   -o namespace03
namespace03.cpp: In function ‘int main()’:
namespace03.cpp:20:11: error: reference to ‘y’ is ambiguous
namespace03.cpp:13:10: error: candidates are: double second::y
namespace03.cpp:7:7: error:                 int first::y
make: *** [namespace03] Error 1

Может кто-нибудь объяснить, почему использование директивы ведет себя по-разному, когда оно используется внутри main и снаружи main?

Ответ 1

Использование-декларация - это просто объявление. using second::y; внутри main похож на объявление переменной y в этой области, которая скрывает любой другой y в глобальной области пространства имен. Когда вы используете using second::y; в глобальной области видимости, вы не скрываете никаких имен, поскольку оба y находятся в одной области.

Представьте, что ваш первый пример выглядит следующим образом (см. пояснения ниже):

namespace first
{
  int x = 5;
  int y = 10;
}

int main () {
  using namespace first; // This makes first::y visible hereafter
  int y = 20; // This hides first::y (similar to using second::y)
  cout << x << endl;
  cout << y << endl; // Prints 20 
}

Однако второй пример выглядит так:

namespace first
{
  int x = 5;
  int y = 10;
}
using namespace first; // This makes first::y visible in global scope
int y = 20; // This is global ::y
int main () {
  cout << x << endl;
  cout << y << endl; // Error! Do you mean ::y or first::y?
}

Ответ 2

Существует два основных отличия между использованием-декларации и директивой use.

Первая разница: (Очевидное различие).

namespace first{

int x=1;
int y=2;
}
using first::x; //using declaration

Это позволит вам использовать переменную x без namespace-name как явный определитель, и обратите внимание, что это не включает y.

namespace first{
int x=1;
int y=2;
}
using namespace first;// using directive

Это позволит вам использовать всю переменную внутри пространства имен first без namespace-name как явный классификатор.


Второе различие: (что вы не понимаете).

Я объясню вам, почему, когда вы используете как служебную, так и служебную декларацию внутри основной функции, вы не получаете никаких ошибок, но когда вы пытаетесь использовать их в глобальном пространстве имен, вы получаете ошибку времени компиляции. < бр /" >

Допустим, у нас есть два пространства имен, определенных в глобальном пространстве имен, например:

namespace first
{
  int x = 5;
  int y = 10;
}

namespace second
{
  double x = 3.1416;
  double y = 2.7183;
}


Пример 1:

int main () {    
using namespace first;
using second::y;
  cout << x << endl; // this will output first::x;
  cout << y << endl; // this will output second::y;
  return 0;
}

Причина в том, что директива using using second::y сделает вашу переменную y похожей на нее локальной переменной на область, где используется using-directive, в этом случае она используется внутри основной функции. В то время как использование объявления using namespace first сделает переменные, которые определены внутри этого пространства имен first, выглядят как глобальные переменные, и это допустимо только внутри области, где использовалась директива using, в этом случае она находится внутри основной функции.

поэтому, если вы примените сказанное выше, вы узнаете, что если вы сделали что-то вроде этого:

Пример 2:

 using namespace first;
 using second::y;

 int main () {    
  cout << x << endl; 
  cout << y << endl; // two definitions of y. first::y and second::y 
  return 0;
}

Вы получите сообщение об ошибке, так как оба first::y и second::y будут вести себя так, как если бы они были определены в глобальном пространстве имен, так что вы закончите с нарушением правила One Defintion.