Использование шаблонов или макросов C++ для генерации функций времени компиляции

У меня есть код, который работает во встроенной системе, и он должен работать очень быстро. Я знаю C и макросы, и этот конкретный проект написан в основном на C, но он также использует шаблоны C++ [все чаще]. Есть встроенная функция:

inline my_t read_memory(uint32 addr) {
  #if (CURRENT_STATE & OPTIMIZE_BITMAP)
    return readOptimized(addr);
  #else
    return MEMORY[addr];
  #endif
}

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

#define STATE_A 0x0001
#define STATE_B 0x0010
#define STATE_C 0x0100
#define STATE_D 0x1000

#define OPTIMIZE_BITMAP 0x1010 // optimize states d and b

и во время выполнения (хорошо, компиляция) я попытался переопределить CURRENT_STATE следующим образом:

int main(){
  #define CURRENT_STATE STATE_A
  do_a();
  #undef CURRENT_STATE
  #define CURRENT_STATE STATE_B
  do_b();
  ....
}

Все функции do_X() делают вызовы read_memory(). Я не мог заставить этот подход работать. Значение текущего состояния всегда равно STATE_A, как я вижу, когда использую операторы #warning. Это не мой вопрос, хотя, если вы можете помочь мне с этим, я буду вдвойне счастлив. Итак, мой вопрос: есть ли способ сделать что-то подобное, используя шаблоны вместо макросов?

Еще немного информации: я должен использовать встроенную функцию, потому что я не могу экспортировать MEMORY[] и это библиотечная функция. Я действительно предпочитаю не изменять прототип функции (например, read_memory()...), но это сойдет. Кроме того, простите мою неясность.

огромное спасибо,


person perreal    schedule 13.07.2010    source источник
comment
Почему вы хотите использовать шаблоны для этого?   -  person    schedule 14.07.2010
comment
Это то, что я мог бы придумать для решений во время компиляции, поскольку я не хочу принимать решения во время выполнения. Но я открыт.   -  person perreal    schedule 14.07.2010
comment
Хорошо, что заставляет вас думать, что решение во время выполнения будет слишком медленным? Вы профилировали такую ​​вещь? Мы все хотим, чтобы наш код работал очень быстро и в 99,99% случаев именно так, как он и делает, без экзотического использования макросов или шаблонов.   -  person    schedule 14.07.2010
comment
Это код cuda, и мне сказали свести к минимуму операторы if, но, возможно, мне сначала нужно его профилировать, спасибо.   -  person perreal    schedule 14.07.2010
comment
Как выяснилось в комментариях ниже, perreal пишет библиотеку, а функции do_X() на самом деле представляют собой пользовательский код.   -  person Georg Fritzsche    schedule 14.07.2010


Ответы (2)


Встроенная функция будет проанализирована один раз в той точке единицы перевода, где она объявлена, и будет использовано состояние макросов в этой точке. Многократный вызов функции с макросами, определенными по-разному, не изменит определение функции.

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

template<unsigned state>
inline my_t read_memory(uint32 addr) {
  if(state & OPTIMIZE_BITMAP)
    return readOptimized(addr);
  else
    return MEMORY[addr];
}

int main(){
    read_memory<STATE_A>(some_addr);
    read_memory<STATE_B>(some_addr);
    ....
}

Компилятор поймет, что state & OPTIMIZE_BITMAP является константой, и оптимизирует ту или иную ветвь if для каждого экземпляра шаблона.

person Anthony Williams    schedule 13.07.2010
comment
А так как state и OPTIMIZE_BITMAP являются константами, весьма вероятно, что компилятор вообще исключит тест и мертвый код, тем самым достигнув того же эффекта. - person Matthieu M.; 14.07.2010

Я думаю, вы можете неправильно понять, что компилятор (точнее, препроцессор) делает с #define.

Ваш пример (приведенный ниже) бесполезен, потому что CURRENT_STATE не используется между #define и #undef. В этот момент препроцессор не «выполняет» ваш код и не расширяет встроенную функцию do_a(). #define и раскрытие макросов могут происходить ТОЧНО В ПОРЯДКЕ СТРОК В ВАШЕМ ИСТОЧНИКЕ.

  #define CURRENT_STATE STATE_A
  do_a();
  #undef CURRENT_STATE

Вот решение на основе препроцессора, если шаблоны наводят вас на ужас. Предположим, что do_a() следует использовать оптимизированную версию.

inline my_t read_memory(uint32 addr) 
{
  return MEMORY[addr];
}

inline my_t read_memory_optimized(uint32 addr) 
{
  return readOptimized(addr);
}

Теперь создайте DO_CONFIG.H

#if defined(DO_A) || (defined(DO_C) || ...)
  #define READ_MEMORY read_memory_optimized
#else
  #define READ_MEMORY read_memory

В DO_A.C добавьте это вверху

#define DO_A
#include DO_CONFIG.H

...и используйте x=READ_MEMORY(addr) вместо x=read_memory(addr). Чтобы переключиться с оптимизированного на неоптимизированный, просто измените DO_CONFIG.H

person Roddy    schedule 13.07.2010
comment
@perreal. Вы задаете вопросы здесь. Это СМАРТ! - person Roddy; 14.07.2010
comment
так что, возможно, что-то вроде #define CURRENT_STATE STATE_A #include usr_do_a.c do_a(); #undef CURRENT_STATE ... будет работать? куча файлов... - person perreal; 14.07.2010
comment
@per: Пожалуйста, не надо, это будет очень некрасиво. Нельзя ли вместо этого использовать шаблоны функций do_X()? Это было бы намного чище. - person Georg Fritzsche; 14.07.2010
comment
@perreal - это все равно не будет работать, если read_memory() не определено как статическое в каждом из ваших файлов do_x.c - person Roddy; 14.07.2010
comment
@Roddy, @Georg: я понимаю вашу точку зрения, моя точка зрения заключается в том, что если пользователь знает, что он должен вызывать разные версии в соответствии со своими потребностями, он может также явно вызывать другую версию. Мое намерение состоит в том, чтобы сделать его полностью прозрачным (да, растровое изображение есть, но оно другое). - person perreal; 14.07.2010