Let's say I'm trying to rename a namespace with lots of symbols in a huge monorepo codebase. I want to go from old_namespace to new_ns, but I can't atomically update every user, and there are so many symbols that it's difficult to even update all definitions in the namespace at once. So I'd like to be able to freely convert things from the old name one at a time.
Is the following temporary hack legal to make it so that anybody can use either name at any time during the transition period? Can it cause problems in some way?
namespace old_namespace {}
namespace new_ns {
using namespace old_namespace;
}
namespace old_namespace {
using namespace new_ns;
}
Yes, using directives explicitly are allowed to be circular. For qualified lookup, see the note in [namespace.qual]/1 and the example in /3. For unqualified lookup, it does of course work (though the standard doesn't discuss it there), but it might not be the same as having things in their original namespaces:
namespace outer {
void f(); // note shadowing
namespace new_ns {}
namespace old_namespace {
using namespace new_ns;
}
namespace new_ns {
using namespace old_namespace;
}
namespace /* old_namespace */ new_ns {
int f;
}
namespace old_namespace {
void g() {++f;} // error: can't increment function outer::f
}
}
Fortunately this doesn't apply to clients outside the namespaces (which would either use qualified lookup or would use their own using directives which would all take effect at the level of the global namespace).
Similarly, as mentioned by Igor Tandetnik, ADL doesn't follow using directives (though it does search (parents of) inline namespaces), so moving a type without moving all the functions that might be found via it will also break things.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With