Reputation: 5239
I am new to namespaces and was trying this from C++ Primer
#include<iostream>
namespace Jill
{
double bucket;
double fetch;
struct Hill{ };
}
double fetch;
int main()
{
using namespace Jill;
Hill Thrill;
double water = bucket;
//double fetch; //<<<<<<<<<<<<//
std::cin>> fetch;
std::cin>> ::fetch;
std::cin>> Jill::fetch;
std::cout<<"fetch is "<<fetch;
std::cout<<"::fetch is "<< ::fetch;
std::cout<<"Jill::fetch is "<< Jill::fetch;
}
int foom()
{
Jill::Hill top;
Jill::Hill crest;
}
When the line marked //<<<<<<<<<<<<//
is not commented I get expected results. i.e. the
local
variable hides the global
and Jill::fetch
. But when I comment it out, there are 2 fetch left . global fetch
and Jill::fetch
. And the compiler gives the error
namespaceTrial1.cpp:17:13: error: reference to ‘fetch’ is ambiguous
namespaceTrial1.cpp:9:8: error: candidates are: double fetch
namespaceTrial1.cpp:5:9: error: double Jill::fetch
namespaceTrial1.cpp:20:26: error: reference to ‘fetch’ is ambiguous
namespaceTrial1.cpp:9:8: error: candidates are: double fetch
namespaceTrial1.cpp:5:9: error: double Jill::fetch
My question is why does the compiler get confused this lead to ambiguity? Why does it not assume fetch
as just Jill::fetch
, since I have added using namespace Jill
at the start of main()
If I use declarative using Jill::fetch;
at the start of main, the issue gets solved. because using Jill::fetch
makes it as if it has been declared at that location. So, its like there is a local fetch
variable. [Am i correct?] Why does using declaration
behave as if the variable was declared at that location and using directive
doesnt?
Upvotes: 5
Views: 810
Reputation: 71979
The using directive modifies name lookup in a way that isn't exactly intuitive to most programmers. The standard says this in [namespace.udir]p2:
During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.
This wording means that names from the namespace do not appear in the current scope, but in some outer scope. In your example the using directive is in the function which is in the global namespace, and the Jill is also in the global namespace, so the names from Jill appears as if they are in the global namespace. (As Joachim said, the names aren't actually introduced there, so they don't immediately conflict with existing names and you only get ambiguous lookups when you actually use them.)
This is a simple case and the compiler gives you an error, which is good. It can actually get more complicated than that.
namespace Outer {
namespace Mid1 { int i = 1; }
namespace Mid2 {
namespace Tricky {
int i = 2;
namespace Inner {
void f() {
using namespace Mid1;
std::cout << i;
}
}
}
}
}
This will output 2, not 1, even though you had the using directive right next to the line referring to i. But the nearest enclosing namespace that contains both Mid1
and the using directive is Outer
, so Mid1::i
acts as if it was declared in Outer
. If you had an Outer::i
it would be shadowed by Tricky::i
, and Mid1::i
fares no better.
An easy solution is to ban using directives and only use using declarations and namespace aliases. They're far more intuitive.
Upvotes: 3
Reputation: 1109
using namespace
will not give priority to names it imports resulting in what you already observed.
Getting ambiguity error here is language design decision: it would be rather dangerous for such prioritization to exist. Imagine that the Jill
namespace is a large one maintained by several developers probably from different organization. You have no or limited control to its contents and still changes to it might silently change the meaning of your program.
Upvotes: 3
Reputation: 64223
[basic.scope.declaration] says that a local variable hides the global, after it's declaration
int j = 24;
int main() {
int i = j, j;
j = 42;
}
the identifier j is declared twice as a name (and used twice). The declarative region of the first j includes the entire example. The potential scope of the first j begins immediately after that j and extends to the end of the program, but its (actual) scope excludes the text between the , and the }. The declarative region of the second declaration of j (the j immediately before the semicolon) includes all the text between { and }, but its potential scope excludes the declaration of i. The scope of the second declaration of j is the same as its potential scope.
This explains why there isn't an error when you declare a local variable.
When the local variable is not declared, then you have a name clash. The compiler can not decide which fetch
to pick, and throws an error.
Upvotes: 2
Reputation: 409176
When you declare a local variable shadowing a global/namespace variable, you explicitly tell the compiler about that. However, when you are using using
the variables of the namespace doesn't actually end up in the local scope.
From the specification (section 7.3.4, point 3):
A using-directive does not add any members to the declarative region in which it appears.
Also (from same section, point 6):
If name lookup finds a declaration for a name in two different namespaces, and the declarations do not declare the same entity and do not declare functions, the use of the name is ill-formed.
Upvotes: 4