此代码将放在头文件中:
template<typename TTT>
inline Permutation<TTT> operator * (const Cycle<TTT>& cy, const Permutation<TTT>& p)
{
return Permutation<TTT>(cy)*p;
}
是否需要inline
来避免链接器错误?
如果此函数不是模板且头文件用于多个.cpp文件,则需要inline
以避免抱怨函数的多个定义的liker错误。似乎链接器忽略了这个模板。
答案 0 :(得分:5)
是否需要
inline
来避免链接器错误?
在功能模板上,没有。模板(如内联函数)受制于更宽松的单一定义规则,该规则允许多个定义 - 只要定义相同且在单独的翻译单元中。
正如您所说,如果您想在标题中定义非模板函数,则需要inline
;非内联函数受一个更严格的单一定义规则的约束,并且在程序中只能有一个定义。
对于血淋淋的细节,这是由C ++ 11 3.2 / 5指定的:
类类型可以有多个定义,内联函数可以 外部链接,类模板,非静态功能模板,静态数据成员 类模板,类模板的成员函数或模板特化 其中一些模板参数未在程序中指定,只提供每个定义 出现在不同的翻译单元中,并且定义满足以下要求。
(“以下要求”基本上说定义必须相同)。
答案 1 :(得分:1)
考虑模板函数(或函数模板,如果您愿意)根本不是函数。它是创建函数的秘诀。仅在实例化模板的时间和地点创建实际功能。所以这里不需要inline
关键字,因为模板函数不会导致多定义链接器错误,因为它们实际上并未定义(从链接器的角度来看),直到它们被使用为止。
答案 2 :(得分:1)
扩展Mike Seymour的回答 - 他在标准中引用的段落(3.2 / 5)引用了一个名为"vague linkage"的概念。基本上,它是一种说法&#34;我们需要在生成的二进制文件中存在某处,但我们在任何特定情况下都没有明确的主页我们正在发布的目标文件。&#34;在现代平台(Windows,ELF系统,如Linux和OS X)上,这是使用称为COMDAT支持的机制实现的,该机制允许编译器简单地生成实例化和其他模糊的链接项(vtable,typeinfos和内联函数体) )根据需要 - 然后链接器可以自由地删除重复项:
在GNU / Linux或Solaris等ELF系统上与GNU ld版本2.8或更高版本一起使用时。 2,或在Microsoft Windows上,这些构造的重复副本将被丢弃 链接时间。这称为COMDAT支持。
这在GCC manual中有更详细的讨论(由于Cfront模型与现代编译器无关,因此引用了剪辑):
C ++模板是第一个需要更多智能的语言功能 环境比通常在UNIX系统上找到的环境。不知怎的,编译器和链接器 必须确保每个模板实例在可执行文件中只出现一次if 它是必要的,而不是其他的。这个问题有两种基本方法, 这被称为Borland模型和Cfront模型。
Borland模型
Borland C ++通过添加等效的代码解决了模板实例化问题 常见的块到它们的链接器;编译器在每个中发出模板实例 使用它们的翻译单元,链接器将它们折叠在一起。优势 这个模型的特点是链接器只需要考虑对象文件本身;那里 无需担心外部复杂性。这个缺点是编译时间是 因为模板代码被重复编译而增加了。为此编写的代码 model往往包含头文件中所有模板的定义,因为它们必须包含 被视为被实例化。