模板函数在哪里实例化?
Where are template functions instantiated?
我相信有4种情况我的问题可能会有不同的答案。这些情况按成员与 non-member 函数以及内部与没有库排序。
Non-member 库中的函数
假设我在headerfunc.h
.
中定义了一个模板函数func
// func.h
template <typename T>
int func(T t){
//definition
}
我#include "func.h"
在同一个project/library/executable的两个cpp
文件中调用
//a.cpp
#include "func.h"
//stuff
int m = func<int>(3);
//stuff
和
//b.cpp
#include "func.h"
//stuff
int n = func<int>(27);
//stuff
我的理解是这两个cpp
文件应该编译成它们自己的object文件。 func<int>
在哪个 object 文件中实例化?为什么不会违反一个定义规则?对于模板的这种基本应用,显式实例化 func<int>
与其使用分开有什么好处吗?
库中的成员函数
假设 func
是某些 class Func
.
的成员函数
// func.h
class Func {
template <typename T>
int func(T t){
//definition
}
};
func
在哪里实例化? func<int>
会被 link 编辑或放置在行内吗?
跨库的成员和 Non-Member 函数
假设 a.cpp
和 b.cpp
位于不同的库中,这些库分别编译,然后 link 编辑成可执行文件。不同的图书馆会自己定义func<int>
吗? link时,为什么不违反一定义规则?
注意:有一个相同标题的相关问题 here,但在特定情况下只有一个 cpp
文件。
In what object file is func<int>
instantiated?
在模板定义可用时调用它或获取其地址的每个目标文件(又名翻译单元)中。
Why will the One Definition Rule not be violated?
因为标准在 [basic.def.odr].13.
中是这么说的
另见 https://en.cppreference.com/w/cpp/language/definition
There can be more than one definition in a program of each of the following: class type, enumeration type, inline function, inline variable (since C++17), templated entity (template or member of template, but not full template specialization), as long as all of the following is true...
For this basic application of templates, is there any benefit to explicitly instantiating func<int>
separate from its use?
在这种情况下,您不会得到内联,但可能会得到更小的代码。如果您使用 link-time 代码生成,那么内联仍可能发生。
在回答问题时,您所有的问题都没有什么不同。无论模板函数是成员函数还是自由函数,它都将在每个编译单元(.cpp 文件)中首次使用(具有给定类型)时实例化。
从编译器的角度来看,这里没有违反 ODR,因为没有两个禁止的模板函数定义。标准明确允许模板函数的多个定义。
然而,您最终在目标文件中定义了两次实例化函数的直觉是正确的。幸运的是,此时 ODR 不适用。相反,这些定义是用 so-called 'weak' 符号生成的 - 告诉链接器这两个符号是相同的,并且可以自由选择一个(或 none 并执行 link-time 优化!)
我相信有4种情况我的问题可能会有不同的答案。这些情况按成员与 non-member 函数以及内部与没有库排序。
Non-member 库中的函数
假设我在headerfunc.h
.
func
// func.h
template <typename T>
int func(T t){
//definition
}
我#include "func.h"
在同一个project/library/executable的两个cpp
文件中调用
//a.cpp
#include "func.h"
//stuff
int m = func<int>(3);
//stuff
和
//b.cpp
#include "func.h"
//stuff
int n = func<int>(27);
//stuff
我的理解是这两个cpp
文件应该编译成它们自己的object文件。 func<int>
在哪个 object 文件中实例化?为什么不会违反一个定义规则?对于模板的这种基本应用,显式实例化 func<int>
与其使用分开有什么好处吗?
库中的成员函数
假设 func
是某些 class Func
.
// func.h
class Func {
template <typename T>
int func(T t){
//definition
}
};
func
在哪里实例化? func<int>
会被 link 编辑或放置在行内吗?
跨库的成员和 Non-Member 函数
假设 a.cpp
和 b.cpp
位于不同的库中,这些库分别编译,然后 link 编辑成可执行文件。不同的图书馆会自己定义func<int>
吗? link时,为什么不违反一定义规则?
注意:有一个相同标题的相关问题 here,但在特定情况下只有一个 cpp
文件。
In what object file is
func<int>
instantiated?
在模板定义可用时调用它或获取其地址的每个目标文件(又名翻译单元)中。
Why will the One Definition Rule not be violated?
因为标准在 [basic.def.odr].13.
中是这么说的另见 https://en.cppreference.com/w/cpp/language/definition
There can be more than one definition in a program of each of the following: class type, enumeration type, inline function, inline variable (since C++17), templated entity (template or member of template, but not full template specialization), as long as all of the following is true...
For this basic application of templates, is there any benefit to explicitly instantiating
func<int>
separate from its use?
在这种情况下,您不会得到内联,但可能会得到更小的代码。如果您使用 link-time 代码生成,那么内联仍可能发生。
在回答问题时,您所有的问题都没有什么不同。无论模板函数是成员函数还是自由函数,它都将在每个编译单元(.cpp 文件)中首次使用(具有给定类型)时实例化。
从编译器的角度来看,这里没有违反 ODR,因为没有两个禁止的模板函数定义。标准明确允许模板函数的多个定义。
然而,您最终在目标文件中定义了两次实例化函数的直觉是正确的。幸运的是,此时 ODR 不适用。相反,这些定义是用 so-called 'weak' 符号生成的 - 告诉链接器这两个符号是相同的,并且可以自由选择一个(或 none 并执行 link-time 优化!)