模板的内联关键字

inline keyword for templates

本文关键字:关键字      更新时间:2023-10-16

此代码将被放置在头文件中:

template<typename TTT>
inline Permutation<TTT> operator * (const Cycle<TTT>& cy, const Permutation<TTT>& p)
{
    return Permutation<TTT>(cy)*p;
}

inline是否有必要避免链接器错误?

如果此函数不是一个模板,并且头文件在多个.cpp文件中使用,则inline是必要的,以避免出现抱怨函数有多个定义的类似错误。对于模板,链接器似乎忽略了这一点。

inline是否有必要避免链接器错误?

在函数模板上,没有。模板与内联函数一样,受一个更宽松的"一个定义规则"的约束,该规则允许多个定义——只要定义相同并且以单独的翻译单位。

正如您所说,如果您想在标头中定义一个非模板函数,那么inline是必要的;非内联函数受更严格的一个定义规则约束,并且在一个程序中只能有一个定义。

对于血腥的细节,这是由C++11 3.2/5:指定的

类类型可以有多个定义,内联函数外部链接,类模板,非静态函数模板,静态数据成员类模板的成员函数,或的模板专用化如果每个定义出现在不同的翻译单元中,前提是定义满足以下要求。

("以下要求"基本上是指定义必须相同)。

考虑一个模板函数(或者函数模板,如果你喜欢的话)根本不是一个函数。这更像是一个创建函数的配方。实际函数仅在模板实例化的时间和位置创建。因此,这里不需要inline关键字,因为模板函数不会导致多定义链接器错误,因为在使用它们之前(从链接器的角度来看)它们并没有被实际定义。

扩展Mike Seymour的回答——他在《标准》中引用的第(3.2/5)段提到了一个称为"模糊联系"的概念。基本上,这是一种说"我们需要在生成的二进制文件中的某个地方存在,但我们在发出的任何特定对象文件中都没有明确的归属。"在现代平台(Windows、ELF系统,如Linux和OS X)上,这是使用一种称为COMDAT支持的机制来实现的,该机制允许编译器根据需要简单地生成实例化和其他模糊的链接项(vtables、typeinfos和内联函数体)——然后链接器可以自由地抛出重复项:

当在ELF系统(如GNU/Linux或Solaris>2)或Microsoft Windows上与GNU ld 2.8或更高版本一起使用时,这些构造的重复副本将在链接时间。这就是所谓的COMDAT支持。

GCC手册中对此进行了更详细的讨论(由于Cfront模型与现代编译器无关,因此省略了引号):

C++模板是第一个需要从环境。不知怎么的,编译器和链接器如果它是需要的,而在其他情况下根本不需要。这个问题有两种基本方法,其被称为Borland模型和Cfront模型。

Borland模型

Borland C++通过添加等效代码解决了模板实例化问题将公共嵌段连接到它们的连接体;编译器在每个使用它们的翻译单元,链接器将它们折叠在一起。优势这个模型的特点是链接器只需要考虑对象文件本身;那里无需担心外部复杂性。这个缺点是编译时间由于重复编译模板代码,因此增加了。为此编写的代码模型倾向于在头文件中包含所有模板的定义,因为它们必须被视为被实例化。