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++.
Related
Suppose we have a class foo from a namespace space which declares a friend function named bar, which is later on defined, like so:
namespace space {
struct foo {
friend void bar(foo);
};
}
namespace space {
void bar(foo f) { std::cout << "friend from a namespace\n"; }
}
To my understanding, friend void bar(foo); declares bar to be a free function inside space taking a foo by value. To use it, we can simply do:
auto f = space::foo();
bar(f);
My understanding is that we don't have to say space::bar, because ADL will see that bar is defined in the same namespace as foo (its argument) and allow us to omit the full name qualification. Nonetheless, we are permitted to qualify it:
auto f = space::foo();
space::bar(f);
which works (and should work) exactly the same.
Things started to get weird when I introduced other files. Suppose that we move the class and the declaration to foo.hpp:
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
}
#endif //PROJECT_FOO_HPP
and the definitions to foo.cpp:
#include "foo.hpp"
#include <iostream>
namespace space {
void bar(foo f) { std::cout << "friend from a namespace\n"; }
}
notice that all I did was I moved (didn't change any code) stuff to a .hpp-.cpp pair.
What happened then? Well, assuming that we #include "foo.hpp", we still can do:
auto f = space::foo();
bar(f);
but, we are no longer able to do:
auto f = space::foo();
space::bar(f);
This fails saying that: error: 'bar' is not a member of 'space', which is, well, confusing. I am fairly certain that bar is a member of space, unless I misunderstood something heavily. What's also interesting is the fact that if we additionally declare (again!) bar, but outside of foo, it works. What I mean by that is if we change foo.hpp to this:
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
void bar(foo); // the only change!
}
#endif //PROJECT_FOO_HPP
it now works.
Is there something with header / implementation files that alters the expected (at least for me) behaviour? Why is that? Is this a bug? I am using gcc version 10.2.0 (Rev9, Built by MSYS2 project).
There's a slight subtlety that the friend declaration, while it doesn't require a previous declaration of the function or class your class is befriending, does not make the function visible for lookup except via ADL.
cppreference:
A name first declared in a friend declaration within a class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.
This is why you're able to find bar(f) (performs ADL) but not space::bar(f) (fully qualifying the name means ADL is not invoked).
Calling code that doesn't find bar via ADL needs to see a declaration. In the version where everything is in one file, calling code will see the entire definition of space::foo. When you split it into an HPP and a CPP file, calling code only sees the friend declaration which provides limited accessibility.
As you identified, if you want to make the function visible via ordinary lookup, put a declaration of foo in "foo.hpp":
#ifndef PROJECT_FOO_HPP
#define PROJECT_FOO_HPP
namespace space {
struct foo {
friend void bar(foo);
};
void bar(foo); // Now code that includes foo.hpp will see a declaration for bar
}
#endif //PROJECT_FOO_HPP
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.
Why is it an issue when an object defined in the file scope has the same name as an existing namespace? Why is this ok in the function scope (e.g. inside main)?
Example:
#include <iostream>
namespace foo {
class Foo {};
}
namespace bar {
class Bar {};
}
// foo::Foo foo; // <-- This will give error
int main () {
bar::Bar bar; // <-- This is ok
std::cout << "Program ran successfully" << std::endl;
return 0;
}
The error I get is
ns_main.cpp:11:10: error: ‘foo::Foo foo’ redeclared as different kind of symbol
foo::Foo foo;
^
ns_main.cpp:3:15: error: previous declaration of ‘namespace foo { }’
namespace foo {
This situation is quite easy to achieve if a lot of files are included where a lot of different namespaces have been defined.
Can someone explain this? Thanks!
Cheers
The same identifier can be declared and used in different, possibly nested scopes, but not in the same one. Your problem has nothing to do with the fact that the namespaces are defined at file scope. Moving them into another namespace outer does not solve the error:
#include <iostream>
namespace outer {
namespace foo {
class Foo {};
}
namespace bar {
class Bar {};
}
foo::Foo foo; // <-- This will still give an error
}
int main() {
outer::bar::Bar bar; // <-- This is still ok
}
The variable bar in bar::Bar bar; however belongs to another, more local scope than the namespace bar. The variable foo in foo::Foo foo; and the namespace foo are in the exact same scope.
As most of your variables and namespaces should not not be declared in global/file scope, having many namespaces is not a problem at all.
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);
}