I am working through Bjarne Stroustrup's "The C Programming Language (4th edition)" and I came across an example in section 14.4.6 (Namespaces - Versioning) that I haven't been able to replicate. The example #include
s a namespaced class declaration into another namespace. Here is my simplified attempt at reproducing this example:
// V3.h
namespace V3 {
class C {
public:
void print();
};
}
// V3.cpp
#include <iostream>
#include "V3.h"
using namespace std;
namespace V3 {
void C::print() {
cout << "Hello from C" << endl;
}
}
// Popular.h
namespace Popular {
#include "V3.h"
}
// main.cpp
#include "Popular.h"
int main() {
Popular::V3::C c;
c.print();
}
When I attempt to compile this program I get the following output:
$ g++ main.cpp V3.cpp
/tmp/ccAVnUZi.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `Popular::V3::C::print()'
collect2: error: ld returned 1 exit status
Thus, I'm wondering, is it possible to #include
a namespaced class into another namespace? Or am I failing to reproduce this example for other reasons? I read in a later section (15.2.5) that it may not be possible to do this.
Yes, it's totally possible (though highly questionable). #include
is really nothing more than textual copy-paste. It's as-if your Popular.h
was:
namespace Popular {
namespace V3 {
class C {
public:
void print();
};
}
}
This happens to be legitimate C++ code, there are certainly plenty of cases where it wouldn't be.
Note that this class C
is ::Popular::V3::C
. That's a different, and unrelated, type from the one declared in V3.h
- which is ::V3::C
. The second type has a definition for its print()
function in V3.cpp
.
But that's not the print()
you're calling - you're calling ::Popular::V3::C::print()
(which is, again, a member function of a different type from ::V3::C
) and there's no definition for this function anywhere. So, as a result, you get an undefined reference - you need to add a definition for this thing. Like, say:
// Popular.cpp
#include <iostream>
void Popular::V3::C::print() {
std::cout << "This is bad and I should feel bad about it. :-(" << std::endl;
}
But really, don't #include
things inside of a namespace
unless you have a really strongly compelling reason to do so. You could've instead provided a namespace alias:
#include "V3.h"
namespace Popular {
namespace V3 = ::V3;
}
This would let you still write Popular::V3::C
, which is now actually the same type as ::V3::C
.
Or a type alias:
#include "V3.h"
namespace Popular {
using C = ::V3::C;
}
And here again ::Popular::C
is actually the same type as ::V3::C
.