Given the following header and source, in which a simple function GiveMeATwo
is forward declared in the header test.hpp
, within the namespace SomeNamespace
, why does a conflict occur when trying to bring the function GiveMeATwo
into scope via using SomeNamespace::GiveMeATwo
, prior to defining GiveMeATwo
?
test.hpp
#ifndef _TEST_HEADER_
#define _TEST_HEADER_
namespace SomeNamespace {
int GiveMeATwo();
}
#endif
test.cpp
#include "test.hpp"
using SomeNamespace::GiveMeATwo;
int GiveMeATwo() {
return 2;
}
Compiling with Apple clang version 14.0.0 (clang-1400.0.29.202)
yields the following error, indicating that the using
statement somehow implicitly introduces a declaration?
test.cpp:5:5: error: declaration conflicts with target of using declaration already in scope
int GiveMeATwo() {
^
./test.hpp:6:5: note: target of using declaration
int GiveMeATwo();
^
test.cpp:3:22: note: using declaration
using SomeNamespace::GiveMeATwo;
^
1 error generated.
Furthermore, what is the difference between bringing the GiveMeATwo
symbol into scope via using namespace SomeNamespace
, versus using SomeNamespace::GiveMeATwo
as I have done here?
CodePudding user response:
To quote cppreference:
If an entity is declared, but not defined in some inner namespace, and then declared through using-declaration in the outer namespace, and then a definition appears in the outer namespace with the same unqualified name, that definition is a member of the outer namespace and conflicts with the using-declaration
In other words, this definition:
int GiveMeATwo() {
return 2;
}
is for another function. If you want to define the one in SomeNamespace
, you still need to name the namespace, even if you wrote using SomeNamespace::GiveMeATwo;
or using namespace SomeNamespace;
before it:
int SomeNamespace::GiveMeATwo() {
return 2;
}
The using-directive (using namespace
) is slightly different because:
Using-directive does not add any names to the declarative region in which it appears (unlike the using-declaration), and thus does not prevent identical names from being declared.
So you can do this:
namespace SomeNamespace {
int GiveMeATwo();
}
using namespace SomeNamespace;
int GiveMeATwo() {
return 2;
}
but it's somewhat useless because a call to GiveMeATwo
is now ambiguous unless you qualify it, like ::GiveMeATwo();
for the outer function or SomeNamespace::GiveMeATwo();
for the inner one.