Search code examples
c++namespacesdeclarationdefinitionname-lookup

Scope of using namespace versus using namespace closure


I'm trying to understand why there is ambiguity in my functions when I use using namespace versus explicitly declaring a namespace enclosure.

Book.h header file:

#ifndef MYBOOK_BOOK_H
#define MYBOOK_BOOK_H 

namespace mybook
{
    void showTitle();
    void showTableOfContents();
}

#endif

My implmenetation file which causes an ambiguity error: Book.cpp

#include "Book.h"
#include <iostream>
#include <cctype>
#include <cstring>

using namespace std;
using namespace mybook;

void showTitle() {
    cout << "The Happy Penguin" << endl;
    cout << "By John Smith" << endl;
}

void showTableOfContents() {
     cout << "Chapter 1" << endl;
     cout << "Chapter 2" << endl;
}

My implementation file which does not have an ambiguity error: Book.cpp

#include "Book.h"
#include <iostream>
#include <cctype>
#include <cstring>

using namespace std;

namespace mybook {

   void showTitle() {
       cout << "The Happy Penguin" << endl;
       cout << "By John Smith" << endl;
   }

   void showTableOfContents() {
        cout << "Chapter 1" << endl;
        cout << "Chapter 2" << endl;
   }
}

I would think that the first scenario of Book.cpp should work because by declaring using namespace mybook at the beginning it is saying that I am now going to implement the functions I defined in the header file. However I get the errors of "error 'showTitle': ambiguous call to overload function could be 'void showTitle(void) or void mybook::showTitle(void)'" and same for my other function showTableOfContents. Why does using namespace mybook in the first scenario not work?


Solution

  • These definitions

    using namespace std;
    using namespace mybook;
    
    void showTitle() {
        cout << "The Happy Penguin" << endl;
        cout << "By John Smith" << endl;
    }
    
    void showTableOfContents() {
         cout << "Chapter 1" << endl;
         cout << "Chapter 2" << endl;
    }
    

    declare two functions in the global namespace.

    So now you have four functions in the global namespace and in the namespace mybook that have identical declarations and due to including the using directive

    using namespace mybook;
    

    the unqualified name lookup finds all four functions. As a result the compiler reports about ambiguity.

    If you want to define the functions that were declared in the namespace mybook then you have to write

    using namespace std;
    using namespace mybook;
    
    void mybook::showTitle() {
        cout << "The Happy Penguin" << endl;
        cout << "By John Smith" << endl;
    }
    
    void mybook::showTableOfContents() {
         cout << "Chapter 1" << endl;
         cout << "Chapter 2" << endl;
    }
    

    that is you need to use qualified names.

    From the C++ 17 Standard (10.3.1.2 Namespace member definitions)

    2 Members of a named namespace can also be defined outside that namespace by explicit qualification (6.4.3.2) of the name being defined, provided that the entity being defined was already declared in the namespace and the definition appears after the point of declaration in a namespace that encloses the declaration’s namespace.

    and (7.3.4 Using directive)

    3 A using-directive does not add any members to the declarative region in which it appears

    Pay attention to that the ambiguity occurred due to unqualified name lookup.

    If you used a qualified name lookup then the compiler found the functions declared in the global namespace (in which case the program would executed successfully) or in the namespace mybook (in this case the compiler or linker would report an error that the functions are not defined).

    Here is a demonstrative program.

    #include <iostream>
    
    namespace mybook
    {
        void f1();
        void f2();
    }
    
    using namespace mybook;
    
    void f1() { std::cout << "::f1();\n"; }
    void f2() { std::cout << "::f2();\n"; }
    
    int main() 
    {
        ::f1();
        ::f2();
    
        return 0;
    }
    

    Its output is

    ::f1();
    ::f2();
    

    If you would write

    mybook::f1();
    mybook::f2();
    

    then an error will occur that the functions are not defined.