2010-11-20 62 views
5

有人here告知這是不可能的,有些人here告知有可能有機器代碼一個版本的模板函數的所有不同的模板參數,所以我認爲這將是有利可圖的,打開有關該特定事項線程如果沒有這樣的可能性,那麼,如果有的話,在什麼情況下我們可以指望呢? 這是特別在兩個提到的線程考慮的一個例子是下面:是否有可能爲模板函數的所有模板參數擁有一個機器代碼版本?

template<size_t num>  
struct Elements{ 
public: 
    SomeType elements[num]; 
}; 

template<size_t num> 
void print(const Elements<num> & elements,size_t size){ 
//all instances do exactly same thing and with regard to Size that determines the size of object 
} 

和當然還有傳值的版本也:

template<size_t num> 
void print(const Elements<num> elements,size_t size){ 
//all instances do exactly same thing and with regard to Size that determines the size of object 
} 
+0

在你的按價值的例子中,將不同的實例摺疊在一起可能是不可能的,因爲元素參數的大小將是不同的。這反過來會影響功能prolog/epilog(堆棧被分配然後清理)。 – Crashworks 2010-11-20 08:42:36

+0

@Crashworks_So堆棧分配不能爲每個函數調用保留不同大小的堆棧幀嗎? – Pooria 2010-11-20 08:51:29

+0

您應該嘗試在調試器的反彙編窗口中查看幾個函數調用,並查看該堆棧是如何分配的。這可能比我能裝進這個小盒子的東西更有啓發性。 =) – Crashworks 2010-11-20 08:54:28

回答

5

智能接頭可以識別當兩個不同的功能體是相同的並將它們組合成一個符號。這在MSVC中稱爲「COMDAT摺疊」,在大多數其他地方稱爲「重複剝離」。例如,以下兩個函數可能會在PPC上進行相同的編譯,儘管它們採用不同的類型,因爲在給定的情況下,類型的大小相同並且行爲相同。

template<typename T> 
GetLowBit(T foo) { return T & 1; } 

GetLowBit<unsigned long>(ulong x); // compiles to "li r4, 1 ; and r3, r3, r4 ; blr " 
GetLowBit<signed long>(long x); // also compiles to "li r4, 1 ; and r3, r3, r4 ; blr " 

,並因此鏈接可以使雙方自己的「名字」的角度去同一個地方,因爲它是,這樣就GetLowBit<unsigned long>一個電話將轉入同一地址爲GetLowBit<signed long>通話。所以,一般來說,可以將不同的模板實例化在一起,所有這些實例都以相同的方式在相同類型的大小上運行。 (特別是存儲指針或枚舉容器往往會得到合併在一起。)

這不只是發生模板功能。一些連接器可以注意到任何兩個函數具有相同的主體時,併合並它們。特別是我看到MSVC趨於崩潰,什麼也不做每一個虛函數,但返回到一個超級功能,例如用於

class A 
{ 
    virtual void nothing() {}; 
} 

class B 
{ 
    virtual void empty() {}; 
} 

我經常看到(在反彙編調試時,別的東西),對於nothing V表項和empty都指向相同的函數體,而函數體又只是一個ret

你能指望嗎?否。這是一個功能,智能連接可能提供功能當它注意到他們。你的鏈接器可能很愚蠢—這裏有很多糟糕的編譯器。它可能只發生在你提供某些命令參數的情況下。對於某些功能可能會發生這種情況,但只有連接器才知道的原因可能不會發生。根據程序中的其他內容,它甚至可能與構建版本不同。

所以一般來說,是的,這可以發生,當它發生時,它可以是一個很好的節省可執行文件的大小。但是除非你對連接器及其所有功能非常熟悉,否則你不能指望它發生。

0

對於大多數正常的模板,這是不可能的。使用模板的全部原因是因爲您需要爲每個模板分別使用不同的機器代碼。在你的具體例子中,編譯器實際上創建了不同的類型,這絕對是不可摺疊的,而在價值接受的情況下(順便提一句,這是瘋了),它需要知道類型會佔用多少空間向上。

0

關於您的具體查詢:如果我需要一個模板類,其中大部分函數不區分模板參數,我通常會創建一個非模板基類。這允許我將大部分方法移入.cc文件而不是頭部,並確保函數副本不會意外增加。

更普遍:如果你發現自己擔心,你可能讓你的模板的許多專門實例由於參數(您size_t num是一個很好的例子),你可能已經發現了一個模板參數應該真的是構造參數。

+0

在這種情況下,它不能是一個構造函數參數,因爲它必須是編譯時常量。 – UncleBens 2010-11-20 10:52:27

+0

如果你說因爲SomeType elements [num]',有什麼阻止你進入'SomeType * elements'和動態分配?畢竟,'std :: vector'不管大小如何作爲模板參數,都是非常類似數組的。 – 2010-11-20 18:21:24

相關問題