2011-06-05 43 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) { ... },在發佈版本中編譯器會優化死代碼。