【问题标题】:Using C++ templates or macros for compile time function generation使用 C++ 模板或宏生成编译时函数
【发布时间】:2010-07-13 20:06:19
【问题描述】:

我有一个在嵌入式系统上运行的代码,它必须运行得非常快。我知道 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()。我无法使这种方法奏效。当我使用#warning 语句时,我可以看到当前状态的值始终是 STATE_A。这不是我的问题,尽管如果你能帮我解决这个问题,我会很高兴。所以,我的问题是,有没有办法使用模板而不是宏来做这种事情?

更多信息:我必须使用内联函数,因为我无法导出 MEMORY[],这是一个库函数。我真的不想修改函数原型(如 read_memory()...),但它会这样做。另外,请原谅我的晦涩。

非常感谢,

【问题讨论】:

  • 为什么要使用模板来做到这一点?
  • 这就是我可以想到的编译时决策,因为我不想在运行时做出决定。但我是开放的。
  • 好的,是什么让您认为运行时决策太慢了?你有没有介绍过这样的事情?我们都希望我们的代码能够“非常快”地运行,并且 99.99% 的时间都可以做到这一点,而无需使用特殊的宏或模板。
  • 这是 cuda 代码,我被告知要尽量减少 if 语句,但也许我必须先对其进行分析,谢谢
  • 在下面的 cmets 中发现,perreal 正在编写一个库,而 do_X() 函数实际上是用户提供的代码。

标签: c++ templates macros inline cuda


【解决方案1】:

内联函数将在翻译单元中声明它的位置解析一次,并且将使用该位置的宏状态。使用不同定义的宏多次调用函数不会改变函数的定义。

可以使用模板执行此操作 --- 如果您将“当前状态”作为模板参数传递,那么您可以在每个调用点使用不同的实例化:

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 &amp; OPTIMIZE_BITMAP 是一个常量,并针对每个模板实例化优化if 的一个或其他分支。

【讨论】:

  • 而且由于stateOPTIMIZE_BITMAP是常量,编译器很可能会将测试和死代码一并消除,从而达到同样的效果。
【解决方案2】:

我认为您可能误解了编译器(或者更确切地说,预处理器)对#defines 的作用。

您的示例(引用如下)没有用,因为#define 和#undef 之间没有使用CURRENT_STATE。预处理器此时没有“执行”您的代码,也没有扩展 do_a() 内联。 #defines 和宏扩展只能完全按照源代码中的行顺序发生。

  #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

【讨论】:

  • @perreal。你在这里提问。这很聪明!
  • 所以,可能类似于 #define CURRENT_STATE STATE_A #include "usr_do_a.c" do_a(); #undef CURRENT_STATE ... 会起作用吗?很多文件...
  • @per:请不要,那样会变得很丑。 do_X() 函数不能被模板化吗?这样会干净得多。
  • @perreal - 除非在每个 do_x.c 文件中将 read_memory() 定义为静态,否则它仍然无法工作
  • @Roddy, @Georg:我明白你的意思,我的意思是如果用户知道他必须根据自己的需要调用不同的版本,那么他不妨明确地调用不同的版本。我的意图是让它完全透明(是的,位图在那里,但它不同)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-24
  • 1970-01-01
相关资源
最近更新 更多