簡體   English   中英

如何在C ++中編譯時打印一個完整的模板參數

[英]How to print an integral template argument at compile time in 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替換為時尚早。

有沒有辦法或沒辦法?

謝謝。

您可以添加一個構建后步驟,在模板的所有編譯完成后查找輸出二進制文件中的所有實例化。 例如,使用GNU工具鏈可以執行以下操作:

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

其中foo是輸出二進制文件的名稱。

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

您甚至可以使用非常廣泛的正則表達式來查找任何類型的所有模板實例:

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

順便提一下,這是一個很好的方式來說明如何使用STL或iostream庫甚至看起來很小的程序。 模板實例化的數量可能真的令人震驚!

由於預處理器階段編譯時模板實例化之前發生,因此您不能讓編譯器根據模板使用預處理器指令執行的操作發出自定義消息。 此外,C ++模板雖然功能非常強大,但在編譯時沒有任何能夠發出自定義消息的能力。

我個人會采用Dan的方法。

如果這不是一個選項,那么就沒有標准的方法,但是在這里擴展其他一些選項,可以讓編譯器為你生成警告,告訴你價值:

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

C<10> c;

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

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

您可以將其置於啟用調試版本的MACRO中。

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

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的位置,而不是其實現,因此錯誤中顯示的代碼片段顯示正在打印其類型的表達式(可以是當你想一次打印幾個不同的時候很方便)。

如果N == 20,你想要一個錯誤嗎?

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

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

以下打印出來:

Test.cpp:在'C <20>'的實例化中:
Test.cpp:14:從這里實例化
Test.cpp:9:錯誤:沒有匹配
呼叫功能
“assertion_failed(MPL _ ::失敗************
(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>();
}

可能會生成警告(例如,在f方法中聲明未使用的空結構的未使用實例)。 但是,只有在實例化該方法時,才會觸發該警告(有希望也提及N的值)(如果有的話)。 另一方面,它可能會根據宏進行有條件編譯。

也許還可以在類聲明中放置一些東西,在實例化類本身時調用警告(例如,不改變實例的大小)。 但是,在使用GCC評估static_assert時,我沒有任何運氣觸發警告。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM