According to this question it is valid to define class methods after a using directive, instead of enclosing them within a namespace block.
However, that seems not to be the case for ordinary functions. Consider:
Greeting.hh
#pragma once
namespace NS
{
class Greeting
{
public:
void hello();
};
void otherHello();
}
Greeting.cc
#include "Greeting.hh"
#include <iostream>
using namespace NS;
void Greeting::hello()
{
std::cout << "Greeting::hello" << std::endl;
}
void otherHello()
{
std::cout << "otherHello" << std::endl;
}
main.cc
#include "Greeting.hh"
int main()
{
NS::Greeting o;
o.hello();
NS::otherHello();
}
This won't compile, yielding the following error message:
undefined reference to `NS::otherHello()'
Further inspection indicates that otherHello's symbol is not preceded by the namespace, while Greeting::hello's is:
g++ -std=c++14 -pedantic -Wall -c Greeting.cc
nm -C Greeting.o | grep T
000000000000002a T otherHello()
0000000000000000 T NS::Greeting::hello()
Does this contradict with the Standard reference from the accepted answer?
"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."
What's important to remember is that
Function declarations in different namespaces don't interfere with each other.
A definition of a function is also a declaration.
[namespace.def/4]
The enclosing namespaces of a declaration are those namespaces in
which the declaration lexically appears, except for a redeclaration of
a namespace member outside its original namespace (e.g., a definition
as specified in [namespace.memdef]). Such a redeclaration has the same
enclosing namespaces as the original declaration.
So let's look at the otherHello definition. Where does it lexically appear? In the global namespace of course. That's also the point of declaration for it. Which means the enclosing namespace is the global one, and you end up with a declaration of ::otherHello.
So no, this doesn't contradict the standard quote from the accepted answer to the other question. Member functions can be defined outside of the class, so long as they are qualified by their class name ([class.mfct/4]):
If the definition of a member function is lexically outside its class
definition, the member function name shall be qualified by its class
name using the :: operator.
So we need only ask, does Greeting name the same class as NS::Greeting? Why, yes it does. The using directive is responsible for that.
I'll add this segment in the hope of clarifying. Consider this code snippet:
namespace NS1 {
namespace NS2 {
void hello();
}
}
using namespace NS1;
void NS2::hello() {
}
int main() {
NS1::NS2::hello();
return 0;
}
When the compiler encounters NS2::hello being defined it preforms name lookup for that declarator id. According to [basic.lookup.qual/3]:
In a declaration in which the declarator-id is a qualified-id, names
used before the qualified-id being declared are looked up in the
defining namespace scope; names following the qualified-id are looked
up in the scope of the member's class or namespace.
So NS2 is looked up in the defining scope (the global one), and according to the unqualified name lookup rule you quoted, it is found and resolved as NS1::NS2. That's how NS2::hello is associated with NS1::NS2::hello and resolved as defining it.
In the global namespace of the OP, otherHello isn't preceded by anything. Therefore name lookup doesn't occur. It immediately defines that function in the enclosing namespace, as I previously quoted.
Related
Can someone explain why I can't define variable that was declared in anonymous namespace as global variable in another place?
#include <iostream>
namespace {
extern int number;
}
int number = 123;
void g() {
std::cout << number;
}
Compiler says that "Reference to 'number' is ambiguous" but I can't understand why it recognises declaration and definition as different things? Thank you in advance.
In general, the name being declared by a declaration is not looked up—after all, you can’t rely on finding a previous declaration when a name is first introduced. Of course, there is a similar process that traps things like
int x;
float x;
However, since it isn’t lookup it is not affected by using at all (including for an unnamed namespace). Another way of describing this distinction is that a declaration puts entities into namespaces and thus need not consider any other namespace in order to decide where to put an entity.
There are also cases where lookup does occur for (what might be) a declarator-id:
namespace N {using X=int;}
// using namespace N;
struct A {
A(X()); // ?
};
A has a member function with no parameters returning an A named X (with meaningless parentheses around its declarator); however, with the using-directive it instead has a constructor that takes a pointer to a function of no parameters returning an int. Similarly, in a declaration beginning
template<>
struct X<…
X must be fully looked up, even though a declaration of an explicit specialization must inhabit the same scope as the primary template (with leeway for inline namespaces), because it might continue
template<>
struct X<int>::Y<char> {…};
and not be a specialization of X at all.
For the unqualified name-lookup the compiler considers also nested unnamed namespaces in the global namespace,
You declared two different objects with the same name in the global namespace and in the nested unnamed namespace.
The using directive for unnamed namespace is implicitly inserted in the enclosing namespace.
Consider the following demonstration program
#include <iostream>
namespace N
{
extern int number;
}
using namespace N;
int number = 123;
int main()
{
std::cout << number << '\n';
}
The compiler will issue an error due to the ambiguity for the unqualified reference to the name number in this statement
std::cout << number << '\n';
The similar situation takes place with an unnamed namespace because the using directive is implicitly inserted in the enclosing namespace.
From the C++ 20 Standard (9.8.2 Namespace definition)
7 Members of an inline namespace can be used in most respects as
though they were members of the enclosing namespace. Specifically, the
inline namespace and its enclosing namespace are both added to the set
of associated namespaces used in argument-dependent lookup (6.5.3)
whenever one of them is, and a using directive (9.8.4) that names
the inline namespace is implicitly inserted into the enclosing
namespace as for an unnamed namespace (9.8.2.2).
Consider the following program:
namespace foo {
namespace sub {
int f();
} // namespace sub
} // namespace foo
namespace bar {
namespace sub {
int g() {
using namespace foo;
return sub::f() + 1;
}
} // namespace sub
} // namespace bar
I expect this to compile, but - it doesn't:
$ g++-6 -c a.cpp
a.cpp: In function ‘int bar::sub::g()’:
a.cpp:12:9: error: ‘f’ is not a member of ‘bar::sub’
return sub::f() + 1;
^~~
a.cpp:12:9: note: suggested alternative:
a.cpp:3:5: note: ‘foo::sub::f’
int f();
^
no luck with clang either:
$ clang++-6.0 -c a.cpp
a.cpp:12:9: error: no member named 'f' in namespace 'bar::sub'; did you mean 'foo::sub::f'?
return sub::f() + 1;
^~~~~~
foo::sub::f
a.cpp:3:5: note: 'foo::sub::f' declared here
int f();
^
1 error generated.
and it knows which function I want, too!
Now, I understand that things could be ambiguous if I had both a foo::sub::f and a bar::sub::f here. But - why is bar::sub "hiding" foo::sub even when I explicitly ask to use foo::sub functions?
To be clear about what an answer might:
An explanation why this is the (most) reasonable behavior and my expectation is unreasonable.
The rationale for it being this way in the C++ standard.
A quotation from standard saying this needs to be the case; maybe the context will help me understand why this was decided.
Motivation: I've written my code so that the last namespace before the function is part of the method name, in the sense that you wouldn't understand what the function does without prepending the namespace. So instead of saying sub_f() like I would in C, I want to be able to say sub::f(). It's proving difficult to do so without prepending a much longer path of namespaces.
[namespace.udir] says (emphasis mine):
-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 (6.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]
In your example "the names in the nominated namespace" is just foo::sub because that's the only name declared in namespace foo, and the "nearest enclosing namespace which contains both the using-directive and the nominated namespace" is the global namespace. So foo::sub appears (for the purposes of name lookup) as though it were in the global namespace, like this:
namespace sub {
int f();
} // namespace sub
namespace bar {
namespace sub {
int g() {
return sub::f() + 1;
}
} // namespace sub
} // namespace bar
Now it should be more obvious that sub::f won't find anything. Name lookup for sub::f starts by looking for sub. It doesn't find it in the enclosing namespace (which is bar::sub) so it looks in the next innermost enclosing scope (which is bar) and there it finds sub. At that point name lookup for sub stops, it doesn't look in the global namespace where it would find foo::sub made visible by the using-directive.
The next step of name lookup tries to find f in the scope it found for sub, but there's no f in the namespace it found, so name lookup fails.
Using-directives do not work like adding a using-declaration for every member of the namespace, they are "weaker" than using-declarations. The reason for that is so that names really declared in a namespace take priority over names simply made visible by a using-directive. rodrigo's answer to a related question explains that in more detail.
I think the relevant part of the standard that prevents what you are trying to do is this:
6.3.10 Name hiding [basic.scope.hiding]
...
4 During the lookup of a name qualified by a namespace name, declarations that would otherwise be made visible by a using-directive can be hidden by declarations with the same name in the namespace containing the using-directive;
You have sub in both foo and bar namespaces. And the sub in bar is hiding the sub in foo in spite of the using directive. And that is the reason why the f() in foo::sub is also not visible.
An answer to your first point:
What happens when you add to your program a:
namespace sub
{
int f();
}
What should now the compiler choose:
::sub::f() or (using ::foo::)sub::f() ?
I have the following class definition in .h file:
namespace N {
struct S {
S(); // no definition for member here
};
}
And I would like to write definition for class constructor (member in general) in .cpp file. I consider the following two cases:
namespace N {
S::S() { /* definition */ }
}
using namespace N;
S::S() { /* definition */ }
I'm slightly confused why the second is working at all, because never saw this way definition until today. Why the second is working? Some citing from the Standard would be appreciated.
What are the nuances of using one approach instead of the other? Should I prefer the first or the second form?
The reason (2) works is because of these two:
[class.mfct]/4
If the definition of a member function is lexically outside its class
definition, the member function name shall be qualified by its class
name using the :: operator.
[namespace.udir]/2 (emphasis mine)
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, 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 ]
The directive simply lets you name S for the :: operator as if you were inside the N namespace (as you are in (1)). But I wouldn't do that. Scoping is good. Definitions should be scoped too.
In this particular example you have declared only one structure in the namespace and defined the function in a separate .cpp file, so it doesn't matter if you use 1 or 2.
Had you declared any other identifiers in the namespace, then 1 should be preferred over 2 as the using declaration kind of defeats the purpose of having a namespace.
Should a reference to a name that exists in both an unnamed namespace and the local named namespace result in a error for ambiguity or is the resolution well-defined? I'm seeing the following work fine on G++ and Clang, less well on MSVC.
namespace Foo
{
class Bar
{
public:
int x;
};
}
namespace
{
class Bar
{
public:
int y;
};
}
namespace Foo
{
void tester()
{
Bar b;
}
}
int main()
{
Foo::tester();
return 0;
}
GCC and Clang are right. Within Foo::tester, an unqualified use of Bar unambiguously refers to Foo::Bar.
Unqualified lookup is specified by C++11 3.4.1/1:
the scopes are searched for a declaration in the order listed in each of the
respective categories; name lookup ends as soon as a declaration is found for the name.
The scopes searched for the use of a name in a function are listed in 3.4.1/6:
A name used in the definition of a function [...] that is a member of namespace N [...] shall be declared before its use in the block [...] or, shall be declared before its use in namespace N or, if N is a nested namespace, shall be declared before its use in one of N’s enclosing namespaces.
In this case, the function is a member of Foo, so Foo is searched before the enclosing (global) namespace, which includes the unnamed namespace. Foo::Bar is found there, and lookup ends.
I've written the following code:
#include <iostream>
inline namespace M
{
int j=42;
}
int main(){ std::cout << j << "\n"; } //j is unqualified name here.
//Hence, unqualified name lookup rules will be applied.
//This implies that member of inline namespace shall not be considered.
//But it is not true
And it works fine. But I'm expected that the that program is ill-formed. It is because the Standard said (N3797, sec. 7.3.1/7):
Finally, looking up a name in the enclosing namespace via explicit
qualification (3.4.3.2) will include members of the inline namespace
brought in by the using-directive even if there are declarations of
that name in the enclosing namespace.
Also the section 3.4.1/6 does not said anything about involving of inline namespace in the unqualified name lookup:
A name used in the definition of a function following the function’s
declarator-id 28 that is a member of namespace N (where, only for the
purpose of exposition, N could represent the global scope) shall be
declared before its use in the block in which it is used or in one of
its enclosing blocks (6.3) or, shall be declared before its use in
namespace N or, if N is a nested namespace, shall be declared before
its use in one of N’s enclosing namespaces.
It is a g++ bug or I understood that rules incorrectly?
There's no bug..
No, it's not a bug in neither g++ (or clang++) which has the behavior described, the compiler is supposed to find j.
inline namespace N {
int j;
}
int main () {
int a = j; // legal, `j` == `N::j`
}
What does the Standard say?
You are missing a very important section of the standard, namely 7.3.1§8, where it states that the enclosing namespace of an inline namespace implicitly has a using directive that refers to the inline namespace.
[7.3.1]p8 namespace definition [namespace.def]
Members of an inline namespace can be used in most respects as thought they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup (3.4.2) whenever one of them is, and a using-directive (7.3.4) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (7.3.1.1).
Elaboration
This means that our previous example is semantically equivalent to the below, where we have introduced a using-directive to bring the names from our nested namespace into the global namespace:
inline namespace N {
int j;
}
using namespace N; // the implicit using-directive
int main () {
int a = j; // legal
}