What are the pro and cons of using two namespaces such as
namespace library1
{
void function1();
}
namespace library1_sublibrary1
{
void function1();
}
instead of
namespace library1
{
void function1();
namespace sublibrary1
{
void function1();
}
}
I would have to fully qualify symbols in the second case, right? Is there any concrete reason (beyond personal taste) why one should be preferred on the other?
Repeating from two comments.
Between the two versions (one: two separate namespaces, two: nested namespaces), there are some differences in name lookup. Most of these can be overcome with either a using-declaration (e.g. using outer::function0;) or a using-directive (e.g. using namespace library1;), but some cannot.
1. unqualified lookup inside the inner namespace
#include <iostream>
namespace outer
{
void function0() { std::cout << "outer::function0" << std::endl; }
namespace inner
{
void test0()
{
function0(); // finds outer::function
}
}
}
namespace another_outer
{
void test0_1()
{
// either
using namespace outer;
// or
using outer::function0;
function0();
}
}
N.B. you can also put the using-directive or using-declaration at namespace scope in another_outer, but some difference remains:
2. stopping unqualified lookup
Unqualified lookup stops in a scope once a name has been found (and then doesn't search the outer scopes). This can be used to hide functions from other scopes. Here's an example of a problem related to this; also see this answer.
void function1() { std::cout << "::function1" << std::endl; }
namespace another_outer
{
void function1() { std::cout << "another_outer::function1" << std::endl; }
}
namespace outer
{
namespace inner
{
void function1() { std::cout << "outer::inner::function1" << std::endl; }
}
void test1()
{
function1(); // finds ::function1
{
using namespace inner;
function1(); // finds (only) outer::inner::function1
}
{
using namespace another_outer;
//function1(); // finds both ::function1 and another_outer::function1
// error: ambiguous call
}
}
}
3. ADL
This isn't about differences between the two variants, but addresses "I would have to fully qualify symbols in the second case, right?".
Argument-dependent lookup happens when you don't qualify the name of a function in a function call. It looks for the name of the function in namespaces (and classes) associated with the arguments.
namespace outer
{
struct ADL {};
void function2(ADL&) { std::cout << "outer::function2" << std::endl; }
namespace inner
{
void function2(ADL const&);
void test2()
{
ADL x;
function2(x); // finds both outer::function2
// and outer::inner::function2
// overload resolution selects outer::function2
}
}
}
int main()
{
outer::ADL x;
function2(x); // finds outer::function2
outer::inner::test2();
// other tests:
outer::inner::test0();
outer::test1();
}
4. Specifically about conflicting symbols
If you have two identical functions (except for the return type) in outer and outer::inner and both are found for some call, that call will be ambiguous. But unqualified lookup might only find one of them:
namespace outer
{
void function3() { std::cout << "outer::function3()" << std::endl; }
namespace inner
{
void function3()
{ std::cout << "outer::inner::function3()" << std::endl; }
void test3()
{
function3(); // only finds outer::inner::function3
}
}
void test3_1()
{
using namespace inner;
//function3(); // finds both outer::function3
// and outer::inner::function3
// error: ambiguous call
using inner::function3;
function3(); // finds (only) outer::inner::function3
}
}
namespace another_outer
{
void function3() { std::cout << "another_outer::function3" << std::endl; }
void test3_1()
{
using namespace outer;
function3(); // still only finds another_outer::function3
using outer::function3;
function3(); // only finds outer::function3
}
}
Related
while trying to implement a metafunction, which needs to exist only if the "abs" function exists for some type, i ran into the folowing problem:
Here are two examples of code i would expect to yield the same results but in fact, they do not:
First example
#include <iostream>
#include <cmath>
using namespace std;
struct Bar{};
template<typename T>
int abs(T& v)
{
return -1;
}
void test()
{
Bar b;
double x = -2;
cout << abs(x) << endl;
cout << abs(b) << endl;
}
int main()
{
test();
}
Yields:
2
-1
Which is what i expect
Second example
#include <iostream>
#include <cmath>
namespace Foo
{
struct Bar{};
using namespace std;
template<typename T>
int abs(T& v)
{
return -1;
}
void test()
{
Bar b;
double x = -2;
cout << abs(x) << endl;
cout << abs(b) << endl;
}
}
int main()
{
Foo::test();
}
Yields:
-1
-1
Why using a namespace here is making the compiler prioritize the "local" abs methodthe over std::abs?
In the second case the using directive places declared names in the nominated namespace in the global namespace for unqualified name lookup. So within the namespace Foo the unqualified name abs declared in this namespace is found. That is the name abs declared in the namespace Foo hides the name abs declared in the global namespace.
From the C++ 14 Standard (7.3.4 Using directive)
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
(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”. — end note ]
The nearest enclosing namespace in the second program is the global namespace.
Below there are two more programs that demonstrate the same principle of the unqualified name lookup when a using directive is used.
#include <iostream>
void s() { std::cout << "The function s() called.\n"; }
struct s
{
s() { std::cout << "The constructor of struct s called.\n"; }
};
void test()
{
s();
}
int main()
{
test();
}
The program output is
The function s() called.
In this demonstration program the declaration of the function s hides the declaration of the structure s.
Second program.
#include <iostream>
namespace N1
{
void s() { std::cout << "The function N1::s() called.\n"; }
}
namespace N2
{
using namespace N1;
struct s
{
s() { std::cout << "The constructor of struct N2::s called.\n"; }
};
void test()
{
s();
}
}
int main()
{
N2::test();
}
The program output is
The constructor of struct N2::s called.
In this case the declaration of the structure with the name s hides the function with the same name s the declaration of which was placed in the global namespace due to the using directive.
For the reason why this takes place you can refer to Vlad's answer. However, if you want to still be able to perform the testing, you can do the testing in separate namespace.
#include <iostream>
#include <cmath>
namespace Foo
{
template<typename T>
int abs(T& v)
{
return -1;
}
}
namespace Test
{
struct Bar{};
using namespace std;
using namespace Foo;
void test()
{
Bar b;
double x = -2;
cout << abs(x) << endl;
cout << abs(b) << endl;
}
}
int main()
{
Test::test();
}
The output is
2
-1
I thought that in a nested namespace, anything that is part of the parent (or global) namespace is considered equally for overload resolution, but this example seems to show otherwise.
This works fine:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
void foo(float) { std::cout << "float\n"; }
namespace NS {
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
The call to foo(0) matches foo(int) since it is a better match and everything works as expected. However, if I move the declaration of foo(float) into the namespace:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
namespace NS {
void foo(float) { std::cout << "float\n"; }
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
The call to foo(0) now calls foo(float)!
I have searched through https://en.cppreference.com/w/cpp/language/overload_resolution and many other such pages to find the rule that explains this, but I seem to be missing it. Can someone please explain which of the many complex overload resolution rules causes this, or is it something else?
EDIT
I just discovered it is even weirder. Even if the foo inside the namespace doesn't match at all, it still won't use the one outside. This just completely fails to compile:
#include <iostream>
void foo(int) { std::cout << "int\n"; }
namespace NS {
void foo(float, float) { std::cout << "float\n"; }
void bar() {
foo(0);
}
}
int main() {
NS::bar();
}
The point is name lookup, which happens before overload resolution.
When the name foo is found at the namespace NS, name lookup stops, the further scopes won't be checked, the global foo won't be found at all. Then there's only one candidate in overload resolution, and int could convert to float implicitly, then NS::foo(float) gets called at last.
(emphasis mine)
name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.
This question got me wondering whether it is ever useful/necessary to fully qualify class names (including the global scope operator) in an out-of-class member function definition.
On the one hand, I've never seen this done before (and the syntax to properly do so seems obscure). On the other, C++ name lookup is very non-trivial, so maybe a corner case exists.
Question:
Is there ever a case where introducing an out-of-class member function definition by
ReturnType (::Fully::Qualified::Class::Name::MemberFunctionName)(...) { ... }
would differ from
ReturnType Fully::Qualified::Class::Name::MemberFunctionName(...) { ... } (no global scope :: prefix)?
Note that member function definitions must be put into a namespace enclosing the class, so this is not a valid example.
A using-directive can cause Fully to be ambiguous without qualification.
namespace Foo {
struct X {
};
}
using namespace Foo;
struct X {
void c();
};
void X::c() { } // ambiguous
void ::X::c() { } // OK
It's necessary if one is a masochist and enjoys writing stuff like this
namespace foo {
namespace foo {
struct bar {
void baz();
};
}
struct bar {
void baz();
};
void foo::bar::baz() {
}
void (::foo::bar::baz)() {
}
}
One can of course write the second overload as foo::foo::bar::baz in global scope, but the question was whether or not the two declarations can have a different meaning. I wouldn't recommend writing such code.
If a using directive is used then there can be a confusing code.
Consider the following demonstrative program
#include <iostream>
#include <string>
namespace N1
{
struct A
{
void f() const;
};
}
using namespace N1;
void A::f() const { std::cout << "N1::f()\n"; }
struct A
{
void f() const;
};
void ::A::f() const { std::cout << "::f()\n"; }
int main()
{
N1::A().f();
::A().f();
return 0;
}
So for readability this qualified name
void ::A::f() const { std::cout << "::f()\n"; }
shows precisely where the function is declared.
The following example is given in N4296::13.3.3 [over.match.best]
namespace A
{
extern "C" void f(int = 5);
}
namespace B
{
extern "C" void f(int = 5);
}
using A::f;
using B::f;
void use()
{
f(3); // OK, default argument was not used for viability
f(); // Error: found default argument twice
}
I tried to write something similar:
#include <iostream>
namespace A
{
void foo(int a = 5){ std::cout << a << "1" << std::endl; }
}
namespace B
{
void foo(int a = 5){ std::cout << a << std::endl; }
}
using A::foo;
using B::foo;
int main()
{
foo(2); //Error
}
DEMO
But I got a compile-time error. Why does the Standard says that it's OK?
The difference is the extern "C", which affects namespace membership of the function:
From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1997/N1138.pdf
What remains is the definition of “same entity” with respect to ‘extern “C”’ language linkage? This is
addressed by 7.5¶6:
“At most one function with a particular name can have C language linkage. Two
declarations for a function with C language linkage with the same function name
(ignoring the namespace names that qualify it) that appear in different namespace scopes
refer to the same function. Two declarations for an object with C language linkage with
the same name (ignoring the namespace names that qualify it) that appear in different
namespace scopes refer to the same object.”
That's because the two functions are imported from their namespace, this means that the same function has 2 definitions, you can solve it like this:
#include <iostream>
namespace A
{
void foo(int a = 5){ std::cout << a << "1" << std::endl; }
}
namespace B
{
void foo(int a = 5){ std::cout << a << std::endl; }
}
int main()
{
A::foo(2);
B::foo(3);
}
I have two namespaces defined in the default/"root" namespace, nsA and nsB. nsA has a sub-namespace, nsA::subA. When I try referencing a function that belongs to nsB, from inside of nsA::subA, I get an error:
undefined reference to `nsA::subA::nsB::theFunctionInNsB(...)'
Any ideas?
Use global scope resolution:
::nsB::TheFunctionInNsB()
#include <stdio.h>
namespace nsB {
void foo() {
printf( "nsB::foo()\n");
}
}
namespace nsA {
void foo() {
printf( "nsA::foo()\n");
}
namespace subA {
void foo() {
printf( "nsA::subA::foo()\n");
printf( "calling nsB::foo()\n");
::nsB::foo(); // <--- calling foo() in namespace 'nsB'
}
}
}
int main()
{
nsA::subA::foo();
return 0;
}
Need more information to explain that error. The following code is fine:
#include <iostream>
namespace nsB {
void foo() { std::cout << "nsB\n";}
}
namespace nsA {
void foo() { std::cout << "nsA\n";}
namespace subA {
void foo() { std::cout << "nsA::subA\n";}
void bar() {
nsB::foo();
}
}
}
int main() {
nsA::subA::bar();
}
So, while specifying the global namespace solves your current problem, in general it is possible to refer to symbols in nsB without it. Otherwise, you'd have to write ::std::cout, ::std::string, etc, whenever you were in another namespace scope. And you don't. QED.
Specifying the global namespace is for situations where there's another nsB visible in the current scope - for instance if nsA::subA contained its own namespace or class called nsB, and you want to call ::nsbB:foo rather than nsA::subA::nsB::foo. So you'd get the error you quote if for example you have declared (but not defined) nsA::subA::nsB::theFunctionInNsB(...). Did you maybe #include the header for nsB from inside namespace subA?