2011-06-05 53 views
2

是否可以选择性地编译代码的某些部分中的模板,还是仅限于预处理器?例如,如果我想删除的代码段与预处理程序,我知道我可以做:有选择地编译宏代码之外的代码

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

反正有做模板一样吗?

以防万一我问错了问题,这是我正在尝试做的。我想在启动应用程序时加载一些代码。通常,我只是使用一个构造函数来完成我想要的任何操作并创建一个静态变量。但是我希望这只发生在调试版本中,并且代码不会在发布版本中运行。我用这个宏创建的代码是用宏创建的,所以我似乎无法在宏中放置“#if 0”并使其正确扩展。

有没有办法在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 

这似乎并不奏效。

EDIT2:原来的问题与它变成的东西完全不同。改变名字,希望它与实际问题更相关。

+0

[有条件的编译时包含/排除基于模板参数的代码的可能的重复?](http://stackoverflow.com/questions/5659064/conditional-compile-time-inclusion-exclusion-of-基于代码的模板参数) – Xeo 2011-06-05 00:41:25

+0

这是重复的,但可悲的是似乎没有解决方案。 :( – Xeo 2011-06-05 00:42:57

+0

现在还不清楚你想要启用或禁用什么,你展示了一个全局变量的例子,但是你的描述涉及到启用或禁用代码,并且涉及到宏,你可以提供一个“不能放” #if 0'你有问题吗? – 2011-06-05 01:04:58

回答

0

鉴于您的编辑,看起来像是让这比以前困难得多。在你定义宏的地方,在那里提供一个#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() 

在所有情况下,该函数的身体仍然会在那里,但因为你永远不会调用它,它其实并不重要。

+0

这似乎工作。带有-O2的g ++将未使用的符号从结果可执行文件中剥离出来。使用默认的g ++参数(不进行优化)会保留未使用的符号并生成更大的可执行文件。 – 2011-06-06 03:35:48

+0

我也刚刚意识到这会导致在g ++中使用-Wall引发警告。所以当它工作时,如果有人使用-Wall,那就不好。 – 2011-06-06 03:46:23

+0

@Jonathan:什么是警告?显然没有使用的功能 – 2011-06-06 03:49:14

1

传统上,“调试”代码将被包裹在这样的块,使用预处理器,而不是编译:

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

...并通过-DDEBUG到预处理器仅用于“调试”版本。

然而,最好能解决“调试”和“发布”版本之间的差异。调试块通常是未解决问题的指标。

我的建议是你完全删除这些条件。

+0

原因是因为我希望它被用于单元测试库,其中嵌入了测试以在主函数之前运行,但在发布构建期间将被删除(因为不会影响性能或崩溃),类似于D处理单元测试的方式,所以这不是关于未解决的问题,而是使它运行程序与运行单元测试以及可选地禁用单元测试一样。 – 2011-06-05 13:47:59

+0

@Jonathan Sternberg:这使得它成为一个更有趣的问题:) – Johnsyweb 2011-06-06 02:21:41

0

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

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

此选择可变MyObject基于所述常数表达式debug的值的类型。

+0

另一个你可以使用的是'enable_if':http://www.boost.org/doc/libs/release/libs/utility/enable_if.html – Sean 2011-06-05 01:10:07

+0

@Sean很好的电话。 – 2011-06-05 01:26:50

3

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