10

給定模板元程序(TMP),C++編譯器是否會生成構建統計信息來計算實例化類的數量?或者有沒有其他方法可以自動獲得這個數字?因此對於例如所述obiquitous階乘自動計算TMP中實例化類的數量?

#include <iostream> 

template<int N> struct fact { enum { value = N * fact<N-1>::value }; }; 
template<> struct fact<1> { enum { value = 1 }; }; 

int main() 
{ 
    const int x = fact<3>::value; 
    std::cout << x << "\n"; 
    return 0; 
} 

我想取回號3(因爲實際上< 3>,事實上< 2>,和事實上< 1>被實例化)。這個例子當然不重要,但是當你開始使用例如Boost.MPL,編譯時間真的爆炸了,我想知道有多少是由於隱藏的類實例。我的問題主要是針對Visual C++,但是對於gcc的回答也是值得讚賞的。

編輯:爲Visual C++從斯蒂芬T. Lavavej的videos/d1reportAllClassLayout之一加入編譯開關,這樣做對輸出文件的grep +字數,但它(一)增加編制我目前非常脆弱的方法次數巨大和(b)正則表達式很難100%正確。

回答

7

我向GCC做了一個one-line change,它使得它在實例化時打印出每個類模板的名稱。您可以直接調用C++前端cc1plus而不使用-quiet標誌以獲得相同的函數模板。

我還沒有想到將其轉化爲適當的GCC選項,但它只是對我自己的源代碼樹進行破解。我正在考慮將它作爲插件來實現,但它並不在我的TODO列表的頂部。

+0

+1。我建議,應該很容易地破解任何開源編譯器,但是實際上以最好的方式證明了它(通過編寫一個實際上可以實現的補丁)。 – abarnert 2012-07-10 01:19:05

+0

謝謝!什麼會更方便(是的,範圍蔓延!)是所有類模板的日誌和它們的實例化的數量,而不僅僅是所有實例的總數或整個列表。也許一個perl腳本來後處理完整的構建日誌是我應該嘗試的。 – TemplateRex 2012-07-10 06:11:58

+1

只是輸出到'awk -F'<''{templates [$ 1] ++} END {for(t in templates)print t,templates [t]}'' – 2012-07-10 09:11:38

2

當然,沒有便攜的方式來做到這一點。

對於大多數編譯器來說,它們有很多方法可以做到這一點。您已經爲MSVC找到了一個。對於gcc,你可以使用gccxml。或者,對於任何開源編譯器(gcc或clang),在實例化時添加代碼非常簡單,可以保持計數,也可以記錄在編譯完成後可以過濾的內容。

對於Clang/LLVM,您可以構建一個掛鉤實例化的插件,該實例化更清晰,但可能實際上還有更多工作。

使用調試符號進行構建,不進行優化,並且不會剝離可能最終會出現每個實例的重名名稱,您可以使用grep。不過,有些編譯器(包括gcc)總是會內聯至少一些方法,不管你是否希望它們。如果你願意修改代碼,你或許可以迫使它產生出來的行實例,也許是這樣的:

template<int N> struct fact { 
    enum { value = N * fact<N-1>::value }; 
    int *dummy() { return &fact<N-1>::value; } 
}; 
+0

謝謝!修改代碼並不是一個真正的選擇,因爲99%的實例化類模板來自Boost.MPL和等,我也希望有一個清晰的計數。 – TemplateRex 2012-07-10 06:12:49

+0

我相信MSVC可以設置爲絕對關閉所有內聯和優化,這意味着您將得到一切的實例化,但我不認爲其他任何編譯器都有這樣的設置。 – abarnert 2012-07-10 17:49:32

1

有由史蒂芬渡邊寫了一個工具,可以用來計數模板實例化的數量。你可以得到它here。基本上,它會修改代碼,以便每次實例化類時都會生成編譯器警告,然後可以使用正則表達式處理結果文本。

+0

謝謝,我會試一試。 – TemplateRex 2012-07-11 13:26:02