Search code examples
c++c++11namespacesinclude

Is it possible to #include a namespaced class into another namespace


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 #includes 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.


Solution

  • 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.