1

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?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
S. Trahl
  • 99
  • 8
  • 1
    Never use "using namespace std". You shouldn't try to figure out how to get it to work and instead just get rid of that practice. – Eric Jan 16 '20 at 16:01
  • 1
    And don't use C headers such as cstring. Use string and the proper tools you have in C++. – Rosme Jan 16 '20 at 16:05
  • Some context for Eric's comment: https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice/26722134#26722134 Note that some people disagree with the idea that you should *never* use `using namespace std`. – Ben Jones Jan 16 '20 at 16:17
  • @Rosme While it is good advice to prefer `std::string` over C strings, not using C headers in general is not good advice. For example there is nothing wrong with using stuff from ``, ``, `` and many others. In OP's case (although it is currently unused) `` also has valid uses, since there are no C++ equivalents for most of the functions it offers. – walnut Jan 16 '20 at 17:06
  • @walnut True. I shouldn't have said that in that way. – Rosme Jan 16 '20 at 18:45

2 Answers2

5

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.

That is where you are incorrect. using namespace mybook; says you are using the names from mybook, not that you are defining/adding names to mybook. To define names in mybook you need to open the namespace and put the definitions in it like you do in your second example.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
0

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.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thank you the examples helped to illustrate to me where I was making a mistake in my understanding. – S. Trahl Jan 16 '20 at 16:43