BRIEF: is it ever safe to do
namespace Foo {
#include "bar"
}
Before you blithely say no, I think I have some rules that allow it fairly safely.
But I don't like them, since they require the includer to separately include all global scope headers needed. Although this mightr be tolerable, if we imagine including within a namespace to be just a special management feature.
And overall, externs and forward declarations just don't work well from within namespaces.
So I gues I am asking
a) What other gotchas
b) is there a better way
== A [[Header-only library]] ==
I like writing libraries. [[Header-only libraries and linker libraries]].
E.g.
#include "Valid.hpp"
defines a template Valid, for a simple wrapper type.
(Don't get bogged down in "You should use some standard library for this rather than your own. This is an exanple. I dunno if Boost or C++ have yet standardized this. I have been using wrappers since templates were added to C++.)
Also, let us say, it is a header only library, that defines, in Valid.hpp, a print function
std::string to_string( const Valid& v ) { std::ostringstream oss; if( v.valid() ) { oss << v; } else { "invalid"; } return oss.str(); }
And because I think it is the right thing to do, I have Valid.hpp include the headers it depends on:
Valid.hpp:
#include <iostream>
#include <sstream>
template<typename T>
class Valid {
private:
T value_;
bool valid_
...
};
...
std::string to_string( const Valid<T>& v ) { ...
So far, so good.
I can use Valid straightforwardly.
== Name collision - trying to use include within namespace to work around ==
But sometimes there is a collision. Sometimes somebody else has their own Valid.
Namespaces to the rescue, right? But I don't want to change all of my existing code to use the namespace. So, I am tempted, in a new project that has a collision, to do
namespace AG {
namespace Wrapper {
#include "lib/AG/Wrapper/Valid.hpp"
}
}
AG::Wrapper::Valid<T> foo_v;
...
PROBLEM: the headers included are no longer freestanding. Everything defined inside is no placed inside namespace AG::Wrapper.
It's not hard to "fix".
Al we "must" do is include all the top level libraries that Valid.hpp depends on.
If they have include guards, they will not be re-included.
#include <iostream>
#include <sstream>
namespace AG {
namespace Wrapper {
#include "lib/AG/Wrapper/Valid.hpp"
}
}
AG::Wrapper::Valid<T> foo_v;
...
But it is no longer freestanding. :-(
Worse, sometimes the header-only library contains extern declarations and forward declarations of stuff outside itself. These declarations get placed inside the namespace too. In particular, if the extern declarayion is inside a function defined in the namespace.
I.e. sometimes we use extern and forward declarations, rather than included an entire header file. These get included in the namespace.
Q: is there a better way?
== :: doesn't do it ==
Hint: :: doesn't do it. At least not all the time, not in gcc 4.7.2.
(Gcc's behavior in this has changed over time. Gcc 4.1.2 behaved differently.)
E.g.
Type var;
namespace Foo {
void bar() {
extern ::Type ::var;;
extern ::Type ::Foo::bar;
extern ::Type::foo ::bar; // see the ambiguity?
};
But it's not just the ambiguity.
int var;
namespace Foo {
void bar() {
extern int var;
};
works - Foo::bar'svar is equal to ::var.
But it only works because of the declaration outside the namespace.
The following doesn't work
header int var; cpp namespace Foo { void bar() { extern int var; } }
although the following does:
header int var; cpp void bar() { extern int var; } }
Basically, what this amounts to saying is that it is not a trivial refactoring to put functions inside a namespace. Wrapping a namespace around a chunk of code, whether or not it is #include'd, is not a sufficient. ... at least not if there are extern or forward declarations.
And even if you
== Opinion against putting includes within namespaces ==
Stackoverflow folks seem to be against putting #includes inside namespaces:
E.g. How to use class defined in a separate header within a namespace:
... you should never write a #include inside a namespace. Where "never" means, "unless you're doing something really obscure that I haven't thought of and that justifies it". You want to be able to look at a file, and see what the fully-qualified names are of all the things in it. You can't do that if someone comes along later and sticks an extra namespace on the front by including from inside their namespace. – Steve Jessop Jan 6 '12 at 16:38
Overall question:
Is there any way, from deep within a namespace, to say "and now here are some names that I am depending on from the outside world, not within the namespace."?
I.e. I would like to be able to say
namespace A {
void foo() {
// --- here is a reference to gloal scope extreren ...