C++ 模板的内联关键字

C++ 模板的内联关键字,c++,C++,此代码将放置在头文件中: template<typename TTT> inline Permutation<TTT> operator * (const Cycle<TTT>& cy, const Permutation<TTT>& p) { return Permutation<TTT>(cy)*p; } 模板 内联置换算子*(常数循环&cy,常数置换&p) { 返回置换(cy)*p; } inline是

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

template<typename TTT>
inline Permutation<TTT> operator * (const Cycle<TTT>& cy, const Permutation<TTT>& p)
{
    return Permutation<TTT>(cy)*p;
}
模板
内联置换算子*(常数循环&cy,常数置换&p)
{
返回置换(cy)*p;
}
inline
是否有必要避免链接器错误


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

请考虑模板函数(或函数模板,如果您愿意)根本不是函数。这是一个创建函数的方法。实际函数仅在模板实例化时和实例化位置创建。因此,此处不需要
inline
关键字,因为模板函数不会导致多个定义链接器错误,因为它们在使用之前(从链接器的角度来看)没有实际定义

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

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

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

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

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


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

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

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

这一点将在中进行更详细的讨论(由于Cfront模型与现代编译器无关,因此引用被截断):

C++模板是第一个需要用户提供更多智能的语言功能 在UNIX系统上通常找不到的环境。不知何故,编译器和链接器 必须确保每个模板实例在可执行文件中只出现一次,如果 这是需要的,而不是别的。解决这个问题有两种基本方法, 它们被称为Borland模型和Cfront模型

博尔兰模型

Borland C++通过添加代码等价的方法解决了模板实例化问题。 将公共块添加到其链接器;编译器会在每个文件中发出模板实例 使用它们的翻译单元,链接器将它们折叠在一起。优势 该模型是链接器只考虑对象文件本身;那里 没有外部复杂性可担心。这个缺点是编译时间很短 增加,因为模板代码正在重复编译。为此编写的代码 模型倾向于在头文件中包含所有模板的定义,因为它们必须 被视为被实例化


您知道包含防护(ifdef定义或pragma一次)吗?不要做奇怪的变通方法我说的是链接器错误。所以代码是编译的,但没有链接。我知道。但是,撇开“是否使用模板”不谈,您的问题通常是初学者的错误。不管是否使用模板。这就是为什么我要问,我是否应该解释这一点或更困难的事情。是的,模板是特殊的,必须可见才能实例化。如果不需要内联,可以省略它。@deviantfan不,这与包含防护完全无关。