I have a code snippet:
namespace Work {
void catch_mouse();
}
namespace Tom {
using namespace Work;
void catch_mouse();
}
int main() {
Tom::catch_mouse();
}
The above code works and calls Tom::catch_mouse();
But the same code with using declaration produces an error.
namespace Work {
void catch_mouse();
}
namespace Tom {
using Work::catch_mouse;
void catch_mouse(); // gives an error; conflicting declaration of catch_mouse
}
int main() {
Tom::catch_mouse();
}
As I understand, both using namespace Work
and using Work::catch_mouse
brings the declaration into scope then why the first one compiles and the second one produces error?
CodePudding user response:
There is a subtle difference. A using directive like
using namespace Work;
means that
From the point of view of unqualified name lookup of any name after a using-directive and until the end of the scope in which it appears, every name from namespace-name is visible as if it were declared in the nearest enclosing namespace which contains both the using-directive and namespace-name.
This means that, when the compilers searches catch_mouse
, it will also find it inside the Work
namespace. Specifically, in unqualified name lookup:
For an unqualified name, that is a name that does not appear to the right of a scope resolution operator ::, name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
In your first case, the compiler will first find the catch_mouse()
explicitly declared inside Tom
namespace and then stops the search.
You can convince yourself that this is the case by examining the output of this code:
#include <iostream>
namespace Work {
void catch_mouse() { std::cout << "this is work" << std::endl; }
}
namespace Tom {
using namespace Work;
void catch_mouse() { std::cout << "this is tom" << std::endl; }
}
int main() {
Tom::catch_mouse();
}
See it live on Coliru.
The program prints "this is tom" because the compiler has found the catch_mouse
in Tom.
Your second case
using Work::catch_mouse;
is a using declaration, which (emphasis mine)
makes the symbol member-name from the namespace ns-name accessible for unqualified lookup as if declared in the same class scope, block scope, or namespace as where this using-declaration appears.
This means that you explicitly tell the compiler to "import" the declaration of the Work::catch_mouse
inside the current Tom namespace, as if it were declared here.
But then you have conflicting declaration of catch_mouse
: should the compiler consider inside namespace Tom
the declaration of Work::catch_mouse
or of Tom::catch_mouse
?
This would also leads an ambiguity: when you call catch_mouse()
, should the compiler pick up the Work
or the Tom
versions? Unlike the first case, both declarations of catch_mouse
are on equal footing now.
This is why the code does not compile.
CodePudding user response:
the reason for this behavior is that using a namespace really lets you use the namespace's members without the explicit ::, but using namespace::member is different! it serves as a declaration and is actually called 'using-declarations'. therefor the above code actually declares two functions of the same name and type which leads to the conflicting declaration error.
you can read more about it here under 'using-declarations': https://en.cppreference.com/w/cpp/language/namespace