1

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?

Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • 2
    you could use an alias for the nested namespace: `namespace nested = library1::sublibrary1;`. This would safe a couple of types :) – Manu343726 Oct 10 '13 at 11:08
  • 3
    Besides the personal taste, if `sublibrary1` is in fact a part of `library1` it just seems more logical (to me, oops, there's that personal taste) to structure it the second way. And as a general hint, avoid `using` to pull in whole namespaces into the global namespace. – Some programmer dude Oct 10 '13 at 11:15
  • There are differences in unqualified name lookup inside those sublibrary1 namespaces. You cannot stop unqualified lookup from finding global scope declarations in the first case via a *using-declaration*. If you use ADL, you don't have to fully qualify names of functions that take arguments of types declared in the namespace of the function. – dyp Oct 10 '13 at 11:32
  • I'm interested in this DyP, what is ADL and why in the first case an unqualified lookup would be confused? – Marco A. Oct 10 '13 at 14:15
  • 1
    @DavidKernin (I almost overlooked your response; please prepend the username with `@` to send a notification.) ADL is argument-dependent lookup. When you write `function1(some_argument);`, the name `function1` has to be found, and argument-dependent lookup also searches the namespaces associated with the argument(s). [Here's an example](http://coliru.stacked-crooked.com/a/c541a3c31185cf32) of what I meant in the previous comment. – dyp Oct 11 '13 at 15:06
  • Thanks, make that an answer and I'll mark it. It's enough for my purposes – Marco A. Oct 11 '13 at 15:17

1 Answers1

1

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
    }
}
Community
  • 1
  • 1
dyp
  • 38,334
  • 13
  • 112
  • 177