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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With