Sometimes to make things easier to write and read, I write some local #define macros within functions (for example, #define O_REAL Ogre::Real)
.
Do I need to #undef the local #define to ensure that it stays within a certain block of code? Or does it automatically #undef when it goes out of scope? Does it even have a concept of scope?
I am unsure on how #define works in this case. Now, I have of course experimented with the code and reached certain conclusions but since I am unsure, I would like some expert opinion/advice.
I would say that "should" implies some sort of option, where it is more of a suggestion. Whereas "need to" implies necessity (obviously ;-) which means that any other option leaves something out.
They are both correct. The would one sounds less direct and is probably a good choice if you want to be somewhat polite. Show activity on this post. Would sounds conditional or hypothetical, so it should be used when expressing a possibility rather than an expected event.
The phrase should have to is also used in hypotheticals to mean "should find it necessary to"--in other words, it means "(the subject) is in a situation in which it is necessary to." Here's an example: If passengers should have to evacuate, lights leading to the emergency doors will be illuminated.
Both are correct depending on situation. If your meeting was ongoing and your presence was required (or not required) at that time "do I have to" could have been used. On the other hand if meeting was in future or question of your presence was for future then "will I have to" would have been used.
#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;
}
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;
// ...
}
#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.
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