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.
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
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++.
I have a file decl.h with the following:
namespace foo {
...
class A;
...
}
I want to use the whole of declarations from decl.h, except for class A, as I want to have another class, with the same name, declared and defined inside my def.cpp. I'm looking for something that'd allow me to do this:
# include "decl.h"
using namespace foo;
hiding foo::A;
class A {
...
};
Is there anything like that? Or the only way around is to explicitly make each desired member from foo public in my def.cpp?
Just remove using namespace foo;. That's the whole point of namespaces.
You can't hide members of a namespace, and certainly not when using a using namespace ... statement.
The whole point of namespaces is to avoid naming conflicts like you describe.
So, get rid of the using namespace foo; statement, and wrap the second class A in a different namespace, eg:
#include "decl.h"
//using namespace foo;
namespace defcpp {
class A {
...
};
}
Now def.cpp will know about foo::A and defcpp::A. You just have to qualify which one you want to use whenever you need to use an A. For example:
#include "decl.h"
//using namespace foo;
namespace defcpp {
class A {
...
};
}
class B {
defcpp::A a;
...
};
void doSomething()
{
defcpp::A a;
...
}
I know in C++, we use :: to qualify the namespace for a variable or function, like myNamespace::a. But I notice some usages like ::myFunction(). Does it mean the function belongs to the global namespace?
If the code compiles, then yes, ::myFunction() is referencing the global declaration of myFunction.
This is most commonly used when a local definition shadows your global definition:
namespace local {
int myFunction() {}; // local namespace definition
};
int myFunction() {}; // global definition.
using namespace local;
int main() {
// myFunction(); // ambiguous two definitions of myFunction in current scope.
local::myFunction(); // uses local::myFunction();
::myFunction(); // uses global myfunction();
Yes, it means the variable, type or function following it must be available in the global namespace.
It can be used for example when something is shadowed by a local definition:
struct S {
int i;
};
void f() {
struct S {
double d;
};
S a;
::S b;
static_assert(sizeof(a) != sizeof(b), "should be different types");
}
When defining a function signature in an anonymous namespace within a .hpp, is it valid to place the implementation of that function within the .cpp? When I do so I get an undefined reference error.
Example:
//hpp
#ifndef __BAR_HPP_
#define __BAR_HPP_
namespace foo
{
namespace
{
struct Bar
{
void func();
};
}
}
#endif
//cpp
using foo;
void Bar::func()
{
//...
}
Think of this:
namespace foo
{
struct Bar
{
void func();
};
}
void Bar::func() { /*impl...*/ }
Your code doesn't work for the same reason this code doesn't -- the definition is being provided in the wrong scope. What's needed is:
void foo::Bar::func() { /*impl...*/ }
But what do you put in place of foo:: to refer to the name of an anonymous namespace? It doesn't have one.
Bottom line: it's not possible to declare something inside of an anonymous namespace then define it elsewhere, as no mechanism exists for specifying the proper scope.