Есть ли способ создать макрос препроцессора для функции?

Можно ли создать макрос препроцессора С++ на основе результата функции?

Например, я хотел бы динамически сохранять высоту экрана в определении макроса препроцессора:

#define SCREEN_HEIGHT   GetSystemMetrics(SM_CYVIRTUALSCREEN)

Затем я хочу использовать результат для установки значений в зависимости от высоты экрана:

#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

Это не работает, так как SCREEN_HEIGHT, похоже, не определяется должным образом.

Есть ли лучший способ сделать это? Это вообще возможно? Я хочу иметь возможность получить эту информацию о высоте экрана в заголовочном файле, если это возможно, так как это часть большого фрагмента устаревшего кода.


person devurs    schedule 23.03.2012    source источник


Ответы (4)


Нет. Макросы полностью оцениваются во время компиляции, концептуально, по крайней мере, препроцессором, еще до компиляции фактического кода, а выражения в #if и т. д. должны быть выражениями препроцессора. Высота экрана не может быть известна, пока программа не запустится.

person James Kanze    schedule 23.03.2012

Нет, это невозможно. Как вы ожидаете сделать решение во время компиляции, которое зависит от свойства экрана, на котором будет запускаться приложение? Вы не можете знать это во время компиляции.

person mfontanini    schedule 23.03.2012

Реальные функции обычно вызываются только во время выполнения. Даже такие функции, как sizeofобобщенные константные выражения — благодаря @Pubby на заметку) оцениваются компилятором после этапа предварительной обработки. К этому времени в коде заменены все препроцессорные штучки - компилятор понятия не имеет о таких вещах, как #if. Поэтому то, что вы хотите, невозможно с помощью макросов.

Однако с помощью шаблонов это возможно. Если подумать, то не в этом случае, потому что фактическая высота экрана не может быть известна до момента выполнения.

Вы можете определить структуру, содержащую значения координат в виде констант, и сохранить все это на карте или в другой форме коллекции, а затем динамически просматривать ее во время выполнения, когда вы знаете фактическую высоту экрана.

person Péter Török    schedule 23.03.2012
comment
Функции можно вызывать во время компиляции. - person Pubby; 23.03.2012
comment
@Pubby, спасибо, я этого не знал. Добавил ссылку на соответствующую статью. - person Péter Török; 23.03.2012

Если бы GetSystemMetrics был макросом, вы могли бы сделать это. Если бы GetSystemMetrics было бы constexpr, то вы могли бы использовать трейты.

Но поскольку GetSystemMetrics — это обычная функция, вам придется работать с обычным 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)
person ipc    schedule 23.03.2012