在宏之外的代码中进行选择性编译

Selectively compiling in code outside of a macro

本文关键字:行选 选择性 编译 代码      更新时间:2023-10-16

是否可以使用模板选择性地编译代码的某些部分,或者仅限于预处理器?例如,如果我想用预处理器删除一段代码,我知道我可以做到:

#if 0
static const char[] hello_world = "hello, world";
#endif

有没有对模板做同样的事情?

万一我问错了问题,下面是我要做的。我想在启动应用程序时加载一些代码。通常,我只需要使用构造函数来执行我想要的任何操作,并创建一个静态变量。但我希望这只发生在调试构建中,并且代码在发布构建期间不运行。我正在使用的代码是用宏创建的,所以我似乎无法将"#if0"放入宏中并使其正确展开。

在C++中有这样的方法吗?

编辑:这是我目前使用的宏代码的一个例子。

#define unittest(NAME)                                                  
    struct unittest_ ## NAME :                                          
        public unittest::unittest_template<unittest_ ## NAME>           
    {                                                                   
        unittest_ ## NAME() :                                           
            unittest::unittest_template<unittest_ ## NAME>(#NAME) {}     
        void run_test();                                                
    };                                                                  
    static unittest_ ## NAME NAME ## _unittest;                         
    void unittest_ ## NAME::run_test()

代码是通过以下操作使用的:

unittest(addTest)
{
    assert_(5, 5); // there's an assert statement in the code
}

我喜欢它的语法,但我看不出有什么方法可以使用宏来摆脱函数的主体。我尝试使用开始/结束宏,结果得到:

#ifdef UNITTEST
#  define unittest_begin(NAME) // previous code
#  define unittest_end() // nothing needed
#else
#  define unittest_begin(NAME) #if 0
#  define unittest_end() #endif
#endif

这似乎不起作用。

第二版:原来的问题和原来的完全不同。更改名称,希望它与实际问题更相关。

您需要预处理器条件来消除声明。但如果你只想在函数中间启用/禁用一个块,那没问题。您可以使用模板专门化,但最简单的事情就是使用if (_DEBUG) { ... },在发布版本中,编译器会优化掉死代码。

传统上,"调试"代码会被包装在这样的块中,使用预处理器而不是编译器:

#ifdef DEBUG
// Some debugging code here...
#endif

并且将-DDEBUG传递到预处理器中仅用于"调试"构建。

然而,最好解决"调试"answers"发布"构建之间的差异。调试块通常是未解决问题的指示器。

我的建议是你完全取消这些条件。

考虑到您的编辑,这似乎比必须的要困难得多。在定义宏的地方,提供一个#ifdef块,并选择如何定义它。

#ifdef NDEBUG
#define unittest(NAME) static void dummy_func_##NAME()
#else
#define unittest(NAME)                                                  
  struct unittest_ ## NAME :                                          
      public unittest::unittest_template<unittest_ ## NAME>           
  {                                                                             unittest_ ## NAME() :                                           
          unittest::unittest_template<unittest_ ## NAME>(#NAME) {}     
      void run_test();                                                
  };                                                                  
  static unittest_ ## NAME NAME ## _unittest;                         
  void unittest_ ## NAME::run_test()  
#endif

您也可以在那里使用单个定义,并将main更改为

int main() {
    #ifndef NDEBUG
    unit_tests::run_all_tests(); //or whatever
    #endif
    //regular old code
}

最后一个选项是使用中间宏选择性地声明静态选项本身[不能100%确定这个选项的语法]

#ifndef NDEBUG
#define DECLARE(NAME) static unittest_##NAME NAME##_unittest;
#else
#define DECLARE(NAME) /* noop */
#endif
#define unittest(NAME) 
struct unittest_##NAME { /*add internals*/ }; 
DECLARE(NAME); 
void unittest_##NAME::run_test()

在所有情况下,函数的主体仍然存在,但由于您从未调用过它,所以这并不重要。

您可以使用Boost中的条件元函数。

boost::mpl::if_c <debug, MyDebuggingClass, EmptyClass>::type MyObject;

这基于常量表达式debug的值来选择变量MyObject的类型。