2010-11-20 60 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

相关问题