为什么链接器不抱怨多个函数定义(仅适用于模板化函数)
Why is the linker not complaining about multiple function definitions (only with templated functions)?
pid.h
#include <iostream>
template <class T>
void f(T t);
皮德·
#include "pid.h"
template <class T>
void f(T t) {
std::cout << t;
}
template
void f<int>(int);
PID2.c
#include "pid.h"
template <class T>
void f(T t) {
std::cout << 55;
}
template
void f<int>(int);
主.c
#include "pid.h"
int main()
{
f(1);
return 0;
}
命令:
g++ "-IC:\Users\kam\workspace\boost_1_56_0" -O0 -g3 -pg -Wall -c -fmessage-length=0 -std=c++11 -pthread -o "src\pid2.o" "..\src\pid2.cpp"
g++ "-IC:\Users\kam\workspace\boost_1_56_0" -O0 -g3 -pg -Wall -c -fmessage-length=0 -std=c++11 -pthread -o "src\pid.o" "..\src\pid.cpp"
g++ "-IC:\Users\kam\workspace\boost_1_56_0" -O0 -g3 -pg -Wall -c -fmessage-length=0 -std=c++11 -pthread -o "src\main.o" "..\src\main.cpp"
g++ -pg -o Hello_World.exe "src\pid2.o" "src\pid.o" "src\main.o"
结果:
55
现在,如果我使 pid.c 和 pid2.c 中的函数非模板化,我确实会得到多重定义错误。
我猜链接器没有抱怨,因为它不知道它正在发生。
在翻译单元中编译函数模板的特定实例化时,这些函数被标记为弱符号(使用 ELF 术语(;当链接器看到多个具有相同签名的弱符号时,它会删除除一个定义之外的所有定义。
C++标准要求内联/模板函数的多个定义是相同的 - 著名的一个定义规则。这就是为什么模板和内联函数应始终在头文件中定义的原因。链接器不需要实际检查函数定义是否相同 - 它假定您遵守了规则,因此它可以选择其中任何一个。在这种情况下,它选择了输出55
的版本,但它可以很容易地选择另一个。
都通过提供同一模板函数的两个不同定义来调用未定义的行为,因此当结果与您的期望不符时,您不会抱怨:-(
编辑
但是,非模板、非内联函数在编译时不会标记为弱函数。在这种情况下,只有一个翻译单元(即一个 cpp 文件(可以提供定义。如果您尝试在两个不同的对象文件中定义相同的非模板、非内联函数,则链接器将看到多个"强"定义并给出错误。
正如@jwd在评论中指出的那样,在理想的世界中,链接器将能够诊断您最初违反 ODR 的情况,但除非您使用全程序优化之类的东西,否则这样做并不可行。
相关文章:
- 使用一个参数的模板函数时出错(适用于 2)
- 模板函数仅适用于VS
- 如何使此函数适用于 100 个对象 (c++)?
- 没有适用于 std::unique_ptr 的适当默认构造函数
- 继承函数是否适用于 C++ 中的基类元素或派生类元素?
- 为什么不区分大小写适用于 std::unordered_set的 std::hash 函数?
- 如何创建适用于 lambda 表达式的排序函数
- Qt C++macOS问题。我正在使用函数 .find( "a word") 在多集中搜索单词,它适用于 Windows 但不适用于 mac
- 多态性是否适用于值?或者在按(基)值返回时使用派生类的移动构造函数
- 函数指针数组的类模板参数推导适用于 clang,但不适用于 gcc
- 为什么模板函数只基于返回类型适用于C++
- 是否有适用于 stream2 或 stream3 函数的代码
- 为什么OpenCV构造函数适用于iPhone5而不适用于iPhone6/iPad
- 声明引用适用于类,但不适用于主函数
- 为什么函数模板不理解 NULL,但适用于 nullptr
- 如何获取 Linux 中 mmap() 函数的 FileDescriptor 的内存地址,适用于 Video4Linux
- 在构造函数类中初始化 ofstream,仅适用于 c++11
- C++模板机制来获取函数参数的数量,这将适用于 lambda 和普通函数
- 名称篡改是否适用于c++中的虚拟函数
- 如何在新程序中包含来自其他c++文件的函数(适用于Mac OSX应用程序)