开发者

Using C++ templates or macros for compile time function generation

开发者 https://www.devze.com 2023-01-06 20:39 出处:网络
I have a code that runs on an embedded system and it has to run really fast. I know C and macros, and this particular project is coded mostly in C but it also uses C++ templates [increasingly more]. T

I have a code that runs on an embedded system and it has to run really fast. I know C and macros, and this particular project is coded mostly in C but it also uses C++ templates [increasingly more]. There is an inline function:

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

This function reads from memory in an optimized fashion or conventional fashion based on the current state and a bitmap that tells whether to use optimization in a specific state or not.

#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

and during开发者_开发百科 the course of execution (ok, compilation), I tried to redefine CURRENT_STATE like so:

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

All do_X() functions make read_memory() calls. I could not make this approach work. The value of current state is always STATE_A as I can see when I use #warning statements. This is not my question, although if you can help me with this I'll be double happy. So, my question is, is there a way to do this kind of thing using templates instead of macros?

Some more info: I have to use an inline function because I cannot export MEMORY[] and this is a library function. I really prefer not to modify the function prototype (like read_memory()...) but it will do. Also, pardon my obscurity.

many thanks,


The inline function will be parsed once, at the point in the translation unit where it is declared, and the state of the macros at that point will be used. Calling the function multiple times with the macros defined differently will not change the definition of the function.

You can do this with a template though --- if you pass the "current state" as a template parameter then you can use a different instantiation at each call point:

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);
    ....
}

The compiler will realise that state & OPTIMIZE_BITMAP is a constant and optimize out one or other branch of the if for each template instantiation.


I think you may be misunderstanding what the compiler (or rather, the preprocessor) does with #defines.

Your example (quoted below) is not useful, because CURRENT_STATE is not used between the #define and the #undef. The preprocessor isn't 'executing' your code, or expanding do_a() inline at this point. #defines and macro expansion can only occur EXACTLY IN THE ORDER OF THE LINES IN YOUR SOURCE.

  #define CURRENT_STATE STATE_A
  do_a();
  #undef CURRENT_STATE

Here's a preprocessor-based solution, if templates fill you with horror. Let's assume that do_a() should use the optimised version.

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

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

Now, create DO_CONFIG.H

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

In DO_A.C, add this at the top

#define DO_A
#include DO_CONFIG.H

...and use x=READ_MEMORY(addr) instead of x=read_memory(addr). To switch from optimised to non-optimised, just change DO_CONFIG.H

0

精彩评论

暂无评论...
验证码 换一张
取 消