I looked at this example while trying to understand name lookup :
http://www.gotw.ca/gotw/030.htm . (It is also present in this book -
"More exceptional c++")
As per the article, the recursive call to foo() below at line marked
with "//1" should be ambiguous. However, it is not. It always invokes
N2::foo leading to infinite recursion.
Further, if I replace "using namespace N1" with "using N1::foo" , then
it will call N1::foo . As per the article, this too should be
ambiguous.
Is it a compiler bug (vs 2008 and gcc 4.1) or am i misunderstanding
the article?
Thanks!!
Mayuresh.
---------------------------------------------------------------------------
#include<iostream>
namespace N1
{
void foo()
{
std::cout << "Invoked N1::foo\n";
}
}
namespace N2
{
void foo()
{
using namespace N1;
std::cout << "Invoked N2::foo\n";
foo(); //1
}
}
int main()
{
N2::foo();
}
---------------------------------------------------------------------
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
There is no ambiguity here because there is no König lookup.
>
> Further, if I replace "using namespace N1" with "using N1::foo" , then
> it will call N1::foo . As per the article, this too should be
> ambiguous.
>
> Is it a compiler bug (vs 2008 and gcc 4.1) or am i misunderstanding
> the article?
Not a compiler bug. foo() in N1 (or N2) does not take any parameters.
Nor is a type defined in namespace N1, whose instance is being used in
the recursive call to foo in N2. So König lookup does not kick in
here.
>
Try the following modification:
#include<iostream>
namespace N1
{
struct X {};
void foo(X a)
{
std::cout << "Invoked N1::foo\n";
}
}
namespace N2
{
//using namespace N1;
void foo(N1::X b)
{
std::cout << "Invoked N2::foo\n";
foo(b); //1
}
}
int main()
{
N1::X a;
N2::foo(a);
The case under discussion:
namespace N1 {
void foo() {
std::cout << "Invoked N1::foo\n";
}
}
namespace N2 {
void foo() {
using namespace N1;
std::cout << "Invoked N2::foo\n";
foo(); //1
}
}
(Note all quotes taken from N2588 - a recent draft for C++0x, but I
doubt this has changed significantly)
7.3.4p2 says:
"""
2 A using-directive specifies that the names in the nominated
namespace can be used in the scope in which the using directive
appears after the using-directive. 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. [ Note: in this context, “contains” means
“contains directly or indirectly”. —end note ]
"""
Here the "nearest enclosing namespace" is the global namespace, so
N1::foo appears as if it is ::foo, and is hidden by N2::foo. (I think
I've understood this correctly.)
> Further, if I replace "using namespace N1" with "using N1::foo" , then
> it will call N1::foo . As per the article, this too should be
> ambiguous.
7.3.3p1 says
"""
A using-declaration introduces a name into the declarative region in
which the using-declaration appears. <snip> The member name specified
in a using-declaration is declared in the declarative region in which
the using-declaration appears.
"""
So N1::foo is declared as foo in the block scope, and hides N2::foo.
> Is it a compiler bug (vs 2008 and gcc 4.1) or am i misunderstanding
> the article?
I presume you are referring to the following paragraph in the article:
"""
There is another function with signature f(int), namely the one in
namespace A. If B had written "using namespace A;" or "using A::f;",
then A::f(int) would have been visible as a candidate when looking up
f(int), and the "f(i);" call would have been ambiguous between
A::f(int) and B::f(int). Since B did not bring A::f(int) into scope,
however, only B::f(int) is considered and so the call is unambiguous.
"""
He seems to mean putting the using-directive or using-declaration
directly in namespace B (the equivalent of your namespace N2), which
would certainly be true for the declaration (using A::f) because now
both f's are in the same scope and neither hides the other, but
according to my reading should not happen with the directive (using
namespace A) because then A::f appears as ::f and should be hidden.
Yechezkel Mett
[...]
The concept of scope, and the difference between namespace's
using-directive and using-declaration are the main points here.
Also, yes, this issue has nothing to do with the Koenig lookup.
> As per the article, the recursive call to foo() below at line marked
> with "//1" should be ambiguous.
> However, it is not. It always invokes
> N2::foo leading to infinite recursion.
It depends on how you introduce N1::foo. The following code
won't compile, for name ambiguous.
-------------------------------------------------
#include<iostream>
namespace N1
{
void foo(){std::cout << "Invoked N1::foo\n";}
}
namespace N2
{
using N1::foo; /// <- "A using-declaration"
void foo(){
std::cout << "Invoked N2::foo\n";
foo(); ///1
}
}
int main()
{
N2::foo();
}
-------------------------------------------------
Here, as Yechezkel Mett said, "using N1::foo;" is a
using-declaration, and it will introduce a name, here N1:foo
into the declarative region (inside N2). Therefore we have
two same functions within the same region/scope, which
causes ambiguous.
Also please note "using namespace N1" is a using-directive,
it does change/expand the select scope for the coming
name-lookup. However, in your original example, compilers
can select the best function according to the rules
Yechezkel Mett mentioned.
> Further, if I replace "using namespace N1" with "using N1::foo" , then
> it will call N1::foo . As per the article, this too should be
> ambiguous.
Yes, that the point for the difference between using-directive
and using-declaration. Furthermore, for the scope issue,
------------- just for explanation, won't compile--------------
#include<iostream>
namespace N1
{
void foo(){std::cout << "Invoked N1::foo\n";}
}
using N1::foo; /// <- "A using-declaration"
/// however, will be hidden by N2::foo
namespace N2
{
using N1::foo; /// <- "A using-declaration"
/// ambiguous, as explained above
void foo(){
using N1::foo; /// <- "A using-declaration"
/// will hide N2::foo
std::cout << "Invoked N2::foo\n";
foo(); ///1
}
}
int main()
{
N2::foo();
}
-------------------------------------------------
> Is it a compiler bug (vs 2008 and gcc 4.1) or am i misunderstanding
> the article?
Not a compiler bug. IMHO, "More Exceptional C++" needs full example
and better wording here, since this is a quite confusing topic.
You can Issue a "bug" report to Herb Sutter if you want. :-)
http://www.gotw.ca/publications/mxc++-errata.htm
Jiang