Shorten nested namespace names
If you use nested namespaces, declarations in header files can get very long and unreadable.
//header1
namespace test { namespace test1 {
class Test {};
} } //namespace
In header2 of the program:
#include "header1"
namespace test2 {
class Test1 {
void test(test::test1::Test &test) {}
void test1(test::test1::Test &test) {}
void test2(test::test1::Test &开发者_运维知识库amp;test1, test::test1::Test &test2) {}
};
}
Are there any possibilities to shorten the names in header2?
Here is my favorite technique:
#include "header1"
namespace test2 {
class Test1 {
private:
typedef ::test::test1::Test MeaningfulName;
void test(MeaningfulName &test) {}
void test1(MeaningfulName &test) {}
void test2(MeaningfulName &test1, MeaningfulName &test2) {}
};
}
I make my typedef aliases private, but I put them right at the beginning of the class declaration. It doesn't matter that they're private to the rest of the program because nobody will be using the aliased name, they will be using the actual type name or their own alias for the name.
I also really prefer to use anchored namespace names to avoid later surprises. My rule for this is that I always use an anchored name unless the namespace is one I control and/or is part of the current project or package or whatever. Then I will use the shortest possible relative name. If that relative name would start from the root namespace, I still often use an anchored name.
The main problem is the digraph <:
which will crop up in template declarations a lot once you start using anchored names more often. You have to put in a space to avoid it, especially since digraph processing happens at a really early stage and can give you some very weird error messages.
you can alias namespaces, like this:
namespace tt=test::test1;
There are ways to shorten the names by using aliases or the using
keyword, but they're almost always a bad idea. Namespaces exist for a reason, that reason is to keep things separated. As soon as you put the using
keyword in a header file you break that separation, and there's no point in using namespaces at all. Inside your cpp files you can feel free to have using namespace test1
if you're implementing stuff in test1
, but I would recomend you not do that in your header file as it is the same as putting it at the top of every single cpp file in which that header is included.
What you have to remember is that declaring something in a header is the same as declaring it in every cpp file in which that header is included. It would also be worth asking yourself, "If you're using test1 inside test2 so often, why are they different namespaces?"
In file header2.h
using namespace test::test1;
While this is an old question I feel like I should put forward my solution to this issue, particularly since it's one of the first results that pop-up in google for the subject and may help others.
This method is definitely not the safest as it involves using preprocessor directives but I've taken a liking to using #define and #undef to shorten namespaces in headers.
Here's an example:
#include "header1"
#define shortNS test::test1
namespace test2 {
class Test1 {
void test(shortNS::test &test) {}
void test1(shortNS::test &test) {}
void test2(shortNS::test &test1, shortNS::test &test2) {}
};
}
#undef shortNS
Basically it works by creating a define called "shortNS" that the preprocessor blindly replaces with "test::test1" where ever it occurs after the definition. The issue of course with defining a macro is that it's not limited by scope in any way shape or form, which can wreak havoc and has been known to cause any unsuspecting programmer to loose their mind whilst attempting to debug it.
So to prevent that once we're done with the define we #undef shortNS to tell the preprocessor to stop replacing "shortNS" with "test::test1". This allows us to simulate scope to some degree. In the example above I limited shortNS to the 'scope' of the file.
Here's a brief list of pros/cons off the top of my head.
Pros:
- Allows you to manually limit scope. (Only need it for half a function? Sure.)
- Transparent to anyone including the file.
- No left-over namespace like with "namespace a = b::c"
- No namespace collisions from "using namespace"
- Doesn't bring a namespace into the current namespace (like "using namespace" does)
Cons:
- Any errors in the definition of the shortened namespace will appear wherever it is used never at the macro itself.
- If you include a file inside a #define #undef "block" the define will be used in the included file which may cause unintended results and/or headaches.
- If you forget to #undef it can/will wreck havoc and you will go insane.
- It's a little clunky.
- People who are maintaining your code will hate you.
Long story short, if you're comfortable with macros and don't mind pulling your hair out trying to debug it when it goes wrong, go ahead. The preprocessor is a very, very powerful thing but it's like taping a bit of C4 to your foot and mashing the keypad to set the timer - you don't know when it's going to blow your leg off.
精彩评论