2009-12-01 56 views
3

說我實現了一個模板類,像這樣:如何在編譯時用C打印不可或缺的模板參數++

template <size_t N> class C 
{ 
    void f() 
    { 
     // print out N here? 
    } 
}; 

我希望,而編譯器編譯像

C<20> c; 

一個條款,它將打印出一個消息

「類C的模板與N = 20」

我試着用#pragma和static_assert徒勞。

問題是

  1. 使用#pragma和static_assert,我無法嵌入一個積分(20這裏)進入的消息;
  2. 帶有預處理器,現在還爲時尚早 N尚未被20 所取代。

有沒有辦法或沒有辦法?

謝謝。

回答

1

由於預編譯器階段發生時之前發生模板實例化時,編譯器不能讓編譯器發出基於模板使用預處理器指令的某些內容的自定義消息。而且,C++模板雖然非常強大,但在編譯時沒有任何發送定製消息的能力。

+0

我懷疑這一點。有了一些幻想,你可以將一個或另一個警告修改爲特定的模板診斷。 – hirschhornsalz 2009-12-01 13:27:43

+0

static_assert可以發出消息。這是一個C++ 0x功能,可用於VC++ 10。但是,不可能通過一個完整的部分來推斷。 – 2009-12-01 13:34:04

+0

BOOST_MPL_ASSERT_MSG可以在C++(非0x) – KitsuneYMG 2009-12-01 14:06:16

0

如果N == 20,您是否想要出現錯誤?

如果是這樣,專業化怎麼樣?

template <> class C <20> 
{ 
    int class_C_is_templated_with_20[-1]; 
} 
+0

不,我不希望使用static_assert很容易的ant謂詞。我想要實際的價值。 – 2009-12-01 13:35:34

0

以下打印出:

Test.cpp: In instantiation of ‘C<20>’:
Test.cpp:14: instantiated from here
Test.cpp:9: error: no matching
function for call to
‘assertion_failed(mpl_::failed************
(C<20>::CLASS_C_TEMPLATED_WITH_I_EQUAL_TO_::************)(mpl_::int_<20>))’

此打印出半清晰的消息,但也停止編譯。我不確定這是不是你要找的。

#include <boost/mpl/assert.hpp> 
#include <boost/mpl/int.hpp> 

template<int i_> 
class C 
{ 
public: 

BOOST_MPL_ASSERT_MSG(false, CLASS_C_TEMPLATED_WITH_I_EQUAL_TO_, (boost::mpl::int_<i_>)); 

}; 

int main() { 
C<20>(); 
} 
+0

謝謝,但我的意思是輸出一個有用的消息,而不是停止編譯。對我而言,C <20>應該是合法的。 – 2009-12-02 03:01:31

3

你可以添加一個生成後的步驟,找到輸出二進制中的所有實例化後的模板(一個或多個)的所有彙編完成。例如,使用GNU工具鏈,你可以這樣做:

make 
nm foo | c++filt | grep 'C<[^>]\+>::f' 

哪裏foo是輸出二進制文件的名稱。

顯然需要更改正則表達式才能找到您正在查找的模板實例,但本例適用於您的示例class C

你甚至可以使用非常廣泛的正則表達式來找到所有模板實例,任何一種:

grep '<[^>]\+>::' 

這是偶然一個偉大的方式來說明如何使用STL或iostream的圖書館怎麼漲大,甚至看似小程序。模板實例的數量可以真正令人驚歎!

+0

感謝您的想法。我試着用VC++ 10生成的二進制文件grep,但找不到任何東西。似乎它只適用於g ++。 – 2009-12-02 05:26:41

0

可能會產生警告(例如,在f方法中聲明一個無用空結構的未使用實例)。然而,只有當你實例化該方法時,該警告(希望還會提及N的值)纔會被觸發(如果有的話)。另一方面,它可能是有條件編譯的,具體取決於宏。

也許可以在類實例化時(例如不改變實例的大小)在類聲明中放入某些東西來調用警告。儘管如此,在使用GCC評估static_assert時,我沒有任何運氣觸發警告。

1

我會用Dan's方法親自去。

如果這不是一種選擇,那麼就沒有標準的方法,但這裏的一些其他選項擴展,可以使編譯器生成警告,你會告訴你的價值:

template <int N> class C 
{ 
public: 
    C() 
    { 
    int d1; 
    int d1 = d1; // Using uninitialized variable - warning 
    } 
}; 

C<10> c; 

使用g++-Wuninitialized選項,上面的生成:

t.cc: In constructor 'C<N>::C() [with int N = 10]': 
t.cc:7: warning: 'i' is used uninitialized in this function 

你可以把這個成調試版本啓用宏。

0

通常,生成警告似乎是一種好方法(警告而不是錯誤,因此您可以在一次編譯運行中記錄多個事件)。這是我一直在使用一個功能,它允許傳入的值並獲取其類型的印刷,或傳遞一個類型作爲模板參數:

template <typename T>     
inline void debug_type(const T&) __attribute__((deprecated));   

template <typename T>           
inline void debug_type(const T&) { }       

template <typename T>           
inline void debug_type() __attribute__((deprecated));   

template <typename T>            
inline void debug_type() { } 

您可以使用它像這樣:

debug_type(1); // Pass a value, let the compiler deduce its type 
debug_type<char>(); // Pass a type explicitly 

這導致警告這樣的:

foo.cpp:73:17: warning: 'void debug_type(const T&) [with T = int]' is deprecated (declared at /tmp/arduino_build_static/sketch/Num.h:13) [-Wdeprecated-declarations] 
    debug_type(1); 
       ^
foo.cpp:74:22: warning: 'void debug_type() [with T = char]' is deprecated (declared at /tmp/arduino_build_static/sketch/Num.h:19) [-Wdeprecated-declarations] 
debug_type<char>(); 

的錯誤消息的T = int部分示出的類型(當然其可以是更復雜的模板類型,這僅僅是一個例子) 。

這個警告相對於其他地方提出的未使用變量警告的一個特殊優點是錯誤位置是調用debug_type的地方,而不是它的實現,所以錯誤中顯示的代碼片段顯示了正在打印類型的表達式(當你想一次打印幾個不同的東西時,這可能很方便)。

相關問題