Is it possible to create a C++ preprocessor macro based on a function result?
For example, I'd like to save the screen height dynamically in a preprocessor macro definition:
#define SCREEN_HEIGHT GetSystemMetrics(SM_CYVIRTUALSCREEN)
Then I want to use the result to set values based on the screen height:
#if SCREEN_HEIGHT < 1200
#define TOP_COORD 200
#define BOTTOM_COORD 500
#define LEFT_COORD 0
#define RIGHT_COORD 1280
#else
#define TOP_COORD 1100
#define BOTTOM_COORD 1400
#define LEFT_COORD 0
#define RIGHT_COORD 1280
#endif
This doesn't work, as SCREEN_HEIGHT doesn't seem to be getting defined properly.
Is there a better way to accomplish this? Is this even possible? I want to be able to get this screen height info in the header file if possible, as this is part of a large chunk of legacy code.
No. Macros are fully evaluated at compile time, conceptually at least by a pre-processor, before the actual code is even compiled, and the expressions in #if
, etc. must be preprocessor expressions. The height of the screen cannot be known until the program runs.
No, it can't be done. How do you expect to make a compilation-time desition, which depends on a property of the screen in which the application will be run? You can't know that on compilation time.
Real functions are usually getting called only runtime. Even function-like things such as sizeof
(and generalized constant expressions - thanks to @Pubby for noting) are evaluated by the compiler after the preprocessing stage. By this time all preprocessor stuff has been replaced in the code - the compiler has no idea about things like #if
. Therefore what you want is not possible using macros.
With templates, however, it is possible. On second thought, not in this case, because the actual screen height can not be known until runtime.
You could define a struct to contain the coordinate values as constants, and store all of these in a map or other form of collection, then look it up dynamically at runtime, when you know the actual screen height.
If GetSystemMetrics
would be a macro, then you could do this.
If GetSystemMetrics
would be constexpr
, then you could use traits.
But since GetSystemMetrics
is a normal function, you have to work with normal C++.
struct system_metrics_ {
int top, bottom, left, right;
system_metrics_()
{
if (GetSystemMetrics(SM_CYVIRTUALSCREEN) < 1200) { /* first case */ }
else { /* second case */ }
}
};
// define this method outside the header
const system_metrics_& system_metrics() { static system_metrics_ sm; return sm; }
// legacy code
#define TOP_COORD (system_metrics().top)
#define BOTTOM_COORD (system_metrics().bottom)
#define LEFT_COORD (system_metrics().left)
#define RIGHT_COORD (system_metrics().right)