I have this sample code
namespace ns1
{
void foo(int)
{
}
}
namespace ns2
{
void foo()
{
}
void bar()
{
using namespace ::ns1;
foo(42); // why compiler can't just call ns1::foo?
}
}
And it doesn't compile with error:
prog.cpp:16:9: error: too many arguments to function ‘void ns2::foo()’
I found reason of this error in C++ 2003 standard:
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”. ]
Is any rationale for this strange rule? Why names from namespace ns1 can't directly appear in namespace ns2?
I believe this was/is done in an attempt at reducing conflicts and surprises. Names brought into scope by a using directive are visible, but anything that's directly contained in the local scope will take precedence over it.
If you really want to call you function without a qualified ID, you make it visible with a using declaration instead:
namespace ns1 {
void foo(int) { }
}
namespace ns2 {
void foo() { }
void bar() {
using ::ns1::foo;
foo(42); // No problem; calls ::ns1::foo.
}
}
ns1::foo is being hidden by the declaration of ns2::foo
From N3337, §3.3.10/1 [basic.scope.hiding]
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2).
The section you've quoted (§7.3.4/2) is immediately followed by
3 A using-directive does not add any members to the declarative region in which it appears. [ Example:
namespace A {
int i;
namespace B {
namespace C {
int i;
}
using namespace A::B::C;
void f1() {
i = 5; // OK, C::i visible in B and hides A::i
}
}
// more (irrelevant) stuff
}
—end example ]
In your case, the using-directive is introducing the names in ns1 to the common ancestor namespace of where it appears, and that of ns1, meaning the global namespace. It does not introduce them within ns2, so the declaration of ns2::foo hides that of ns1::foo.
If you want ns1::foo to be found, use a using declaration instead.
void bar()
{
using ::ns1::foo;
foo(42);
}
Related
I have the code:
#include <iostream>
class Foo {
};
namespace Bar {
struct Foo {
};
}
namespace Baz
{
void baz(const Foo &)
{
std::cout << "Hello";
}
}
int main()
{
Baz::baz(Bar::Foo());
}
Compiler can't figure out which Foo want to use and produces the error:
main.cpp: In function 'int main()':
main.cpp:23:19: error: invalid initialization of reference of type 'const Foo&' from expression of type 'Bar::Foo'
23 | Baz::baz(Bar::Foo());
| ^~~~~
main.cpp:15:14: note: in passing argument 1 of 'void Baz::baz(const Foo&)'
15 | void baz(const Foo &)
|
Online compiler
Of course the simplest solution is to use either ::Foo or ::Baz::Foo, but I want to fix all possible ambiguities with O(1) lines of code.
My first idea was using namespace Bar inside Baz namespace:
namespace Baz
{
using namespace Baz;
//...
using-declaration: makes the symbol 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.
I expected that all Bar names become part of Baz namespace, and unqualified lookup prefers Baz::Foo. But for some reason it doesn't work
Online compiler
But using Bar::Foo;, in turn, does the trick. And that confuses me even more
namespace Baz
{
using Bar::Foo;
Online compiler
So, my question is: What is the difference between using namespace Bar and using Bar::Foo in this case?
using namespace Bar::Foo would assume that Bar::Foo is a namespace and import everything from that namespace into current scope, ex.
namespace Bar { namespace Foo { ... all names from this namespace would be imported ... } }
using Bar::Foo would import the class Bar::Foo into scope:
namespace Bar { class Foo {...} }
and if you have nested class Foo within class Bar and want to use it without class specifier, then using would look like:
class Bar {
public:
class Foo {};
};
using Foo = Bar::Foo;
// ...
// ... use Foo instead of Bar::Foo ...
cppreference is your friend.
As regards using namespace ns_name; it reads
using-directive: 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 ns_name is visible as if it were declared in the nearest enclosing namespace which contains both the using-directive and ns_name.
As regards using ns_name::name; it reads
using-declaration: makes the symbol 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.
It seems complicated, but it isn't. Furthermore, learning things explained this way (which is close to standardese, I'd say) pays off when it comes to diving into the depths of C++.
Consider the following code:
namespace Foo1 {
void add( int ) {}
void subtract( int ) {}
}
namespace Foo2 {
class Bar {
public:
friend void add( Bar ) {}
};
void subtract( Bar ) {}
void xxx() {
int i = 0;
using namespace Foo1;
add( i ); // Is this an error or not?
subtract( i ); // This is an error due to name hiding
}
}
In the Foo2::xxx() I used the using namespace to be able to access both Foo1::add and Foo1::subtract. The call to the subtract is obviously an error because the Foo2::subtract
hides the name. But the Foo2::add should not really be visible in Foo2 as it can only
be found using ADL and it should not hide the Foo1::add. Is my understanding correct?
I have tried the above code on multiple versions of MSVC and gcc. The former has consistently
rejected the add(i) call but error messages were not clear to me. The latter has consistently accepted it. Which of these (if any) is correct?
I think GCC is right here.
[namespace.memdef] (emphasis mine)
3 If a friend declaration in a non-local class first declares a
class, function, class template or function template the friend is a
member of the innermost enclosing namespace. The friend declaration
does not by itself make the name visible to unqualified lookup
([basic.lookup.unqual]) or qualified lookup ([basic.lookup.qual]).
[ Note: The name of the friend will be visible in its namespace if a
matching declaration is provided at namespace scope (either before or
after the class definition granting friendship). — end note ] If a
friend function or function template is called, its name may be found
by the name lookup that considers functions from namespaces and
classes associated with the types of the function arguments
([basic.lookup.argdep]).
As such, the unqualified add( i ) should not by itself find the declaration of add( Bar ), which means lookup should continue and consider the names brought in by the using directive. And since the argument is not of a class type, ADL is out of the question. I'd conclude that add( Bar ) should not hide add( int ).
As already was pointed to (The C++ 20 Standard, 9.7.1.2 Namespace member definitions)
3 If a friend declaration in a non-local class first declares a class,
function, class template or function template100 the friend is a
member of the innermost enclosing namespace.
So this friend function add is a member of the namespace Foo2. However it is invisible in the namespace Foo2 until a corresponding function declaration appears in the namespace Foo2. And can be found only due to the argument-dependent look-up.
namespace Foo2 {
class Bar {
public:
friend void add( Bar ) {}
};
//..
The name add from the namespace Foo1 would be hidden if you write before the function xxx
namespace Foo2 {
class Bar {
public:
friend void add( Bar ) {}
};
void add( Bar );
//...
That is if the friend function add will be redeclared in the enclosing namespace.
Within the function xxx
void xxx() {
int i = 0;
using namespace Foo1;
add( i ); // Is this an error or not?
subtract( i ); // This is an error due to name hiding
}
the compiler considers the name substract in the following order. At first it looks through the enclosing namespace that is the namespace Foo2. And this namespace has the declared name substract. So the process of searching stops. The overloaded function void substract( int ) is not found because due to the using directive it is considered as a member of the global namespace. That is of the namespace that enclose the namespace specified in the using directive and the namespace that contains the using directive.
You can consider it the following way (due to the using directibe)
// the global namespace
void subtract( int ) {}
namespace Foo2
{
class Bar {
public:
friend void add( Bar ) {}
};
void subtract( Bar ) {}
void xxx() {
int i = 0;
// using namespace Foo1;
add( i ); // Is this an error or not?
subtract( i ); // This is an error due to name hiding
}
}
Instead of the using directive you could use a using declarations to make the both functions from the namespace Foo1 visible in the function xxx.
For example
void xxx() {
int i = 0;
using Foo1::subtract, Foo1::add;
add( i ); // Is this an error or not?
subtract( i ); // This is an error due to name hiding
}
Given the following:
namespace Foo{
class Bar{
static const auto PRIVATE = 0;
const int private_ = 1;
void ptivateFunc() { cout << 2; }
public:
static const auto PUBLIC = 3;
const int public_ = 4;
void publicFunc() { cout << 5; }
};
}
The statement using Foo::Bar; compiles... But I'm not sure what it's providing me access to. Can anyone explain what the point of that statement would be and what it would give me access to with respect to Bar versus simply doing a using namespace Bar?
From cppreference:
using ns_name::name; (6)
(...)
6) using-declaration: makes the symbol 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.
using namespace ns_name; (5)
5) using-directive: 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.
So basically you can write Bar instead of Foo::Bar outside of the namespace Foo (but inside the scope of the using-declaration), while other symbols from the namespace Foo still need the full name.
If you use using namespace Foo you can access all symbols in Foo by their local name without the explicit Foo::.
It allows you to use Bar without Foo namespace.
namespace A {
void F() {}
namespace B {
void F(int) {}
}
}
using A::B::F;
namespace A {
void G() {
F(); // OK
F(1); // Error: too many arguments to function void A::F()
}
}
int main() { return 0; }
I have this piece of code.
I defined two functions with same names but different signatures.
Then I use a using-declaration using A::B::F.
In A::G() compiler tries to resolve A::F() before A::B::F().
Are there any orders if there are such conflicts?
The deepest nested scope is searched first, and scopes are then searched outward if the name is not found. So first it would find a block-scope declaration of F inside G, if any; then it would find a declaration at the namespace scope of A, if any; and if that too failed it would search the global scope. Since using A::B::F; appears at global scope, A::F is always found first. Perhaps you should move the using declaration inside A.
It's definitely about placement.
namespace A {
void G() {
F(); // OK, A::F
using B::F;
F(1); // OK, A::B::F
}
}
Is this is wrong? Why? May I know what the standard says?
namespace N{
namespace N1{
namespace N2{
struct A{
struct B{
void fun();
};//B
}; //A
} //n2
}//n1
namespace N3{
void N1::N2::A::B::fun(){} //error
}//n3
}//n
int main()
{
return 0;
}
May I know why it is failing?
This is invalid due to §9.3/2:
A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition.
The scope of the namespace N3 does not enclose the definition of the class B
Here is a much simpler example, that also fails to compile:
namespace N1 {
void f() ;
}
namespace N2 {
void N1::f() { }
}
To put the answer in plain English, the definition of a function or method which belongs to a class (or struct) needs to be in the same namespace as the class definition. In other words, you can't declare the function in one namespace and then define it in another.