Sometimes to make things easier to write and read, I write some local #define macros within functions (for example, #define O_REAL Ogre::Real)
.
The scope of a macro is part of compilation unit that comes after #define, up until the end of the unit (which is to say, until the end of .cpp file). However Visual C++ has a pair of #pragma push_macro/pop_macro that can be used in a case where macro definitions overlap. You can push previous definition, define your own, use it, and when you decide just pop previous definition.
Unfortunately, #define
s do not respect scoping rules. #define
s that are not #undef
'd will affect all code after them. Additionally, if code before you defines the same macro name, you'll have problems. In C++ you can usually avoid needing to use such local macros with local typedefs
and references. For example, you could do:
void foo() {
typedef Ogre::Real O_REAL;
// ...
}
This will respect scoping rules. For variables you can use references:
void foo() {
int &BAR = Foo::quux::baz::static_bar;
// ...
}
there is no such thing as a local define
.
Defines are always tentative evil ;-)
For your example I would recommend typedef
to make alias for variable names
However, sometimes local defines
are a nice thing for the programmer (but the are never for the maintainer). To make things a bit easier and a bit safer I always undef
these things and I even guard their entry:
#if defined(LOCAL_CROWBAR)
#error Hurgh!
#endif /* LOCAL_CROWBAR */
#define LOCAL_CROWBAR
... use LOCAL_CROWBAR ...
#undef LOCAL_CROWBAR
Nevertheless, avoid those whenever possible!
#define
does not respect any C++ scope. There is no such thing as a "local" #define
. It'll be in effect until it is #undef
-ed. The preprocessor's macro mechanism is just like the "find-and-replace" functionality found in most text editors; it has no respect for the contents of the file.
In other words, if you want your #define
to be local within a certain block of code, you must #undef
it at the end of that block due to the fact that macros do not "understand" scope.
In fact, that's one of the biggest reasons why macros are discouraged unless they are absolutely necessary in C++. It's why macro names are usually typed in UPPER_CASE
to indicate that it's in fact a macro.
There are actually quite a few macro-less solutions for your specific situation. Consider the following:
namespace ReallyLongOuterNamespace
{
namespace ReallyLongInnerNamespace
{
class Foo {};
void Bar() {}
};
}
void DoThis()
{
// Too much typing!
ReallyLongOuterNamespace::ReallyLongInnerNamespace::Foo f;
ReallyLongOuterNamespace::ReallyLongInnerNamespace::Bar();
}
You can use namespace aliases:
void DoThis()
{
namespace rlin = ReallyLongOuterNamespace::ReallyLongInnerNamespace;
rlin::Foo f;
rlin::Bar();
}
You can also use typedef
s:
void DoThis()
{
typedef ReallyLongOuterNamespace::ReallyLongInnerNamespace::Foo MyFoo;
MyFoo f;
}
You can also use using
declarations:
void DoThis()
{
using ReallyLongOuterNamespace::ReallyLongInnerNamespace::Foo;
using ReallyLongOuterNamespace::ReallyLongInnerNamespace::Bar;
Foo f;
Bar();
}
You can even use a combination of the above!
void DoThis()
{
namespace rlin = ReallyLongOuterNamespace::ReallyLongInnerNamespace;
typedef rlin::Foo MyFoo;
using rlin::Bar;
MyFoo f;
Bar();
}
With respect to Ogre::Real
, it appears to be a typedef
for a float
or a double
. You can still use namespace aliases, typedef
s and using
declarations with typedef
s as well:
void UseOgre()
{
typedef Ogre::Real o_Real; // Yes, you can typedef typedefs.
using Ogre::Real;
/* Or, you can use:
namespace o = Ogre;
typedef o::Real o_Real;
using o::Real;
*/
// All equivalent
Ogre::Real r1;
o_Real r2;
Real r3;
o::Real r4;
}
No. There are no such things as "local" #define
s.
The scope in which the #define
is placed, is unknown at the time as they are processed by the - well - preprocessor. (Hence you sometimes hear the term "preprocessor directive" instead of just "macro".)
#define is handled by the preprocessor, which doesn't actually know C syntax at all. A #define ignores scope, and will remain in effect until you #undef it or until the end of the compilation unit.