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
}
}