gpt4 book ai didi

c++ - 冲突的模板定义和 ODR

转载 作者:行者123 更新时间:2023-11-30 02:23:19 29 4
gpt4 key购买 nike

想象一下我有两个不同的翻译单元 a.cpp

#include <iostream>

double bar();

template <typename T>
T foobar(T t) {
return t;
}

int main() {
std::cout << "foobar called from b.cpp: " << bar() << '\n';
std::cout << "foobar called from a.cpp: " << foobar(1.) << '\n';
}

和 b.cpp:

template <typename T>
T foobar(T t) {
return t + 1.;
}

double bar() {
return foobar(1.);
}

我知道对于模板,ODR 有异常(exception),即编译器将标记实例化的函数模板,并在链接过程中删除除一个之外的所有模板。我注意到编译器实际上并不关心在不同翻译单元上生成的此类实例化代码是否实际上相同或至少相同。

在上面的代码中,是这样的。编译、链接和运行时用

c++ a.cpp b.cpp -o result -std=c++17 && ./result

它会产生结果

foobar called from b.cpp: 1
foobar called from a.cpp: 1

很明显,目标文件 b.o 中的实例化被 a.o 中的实例化所取代。在编译和链接 b.cpp 和 a.cpp 时交换,比如

c++ b.cpp a.cpp -o result -std=c++17 && ./result

结果会是

foobar called from b.cpp: 2
foobar called from a.cpp: 2

所以恰恰相反:在要链接的目标文件列表中首先提到的实例化将是幸存下来的。这种行为是否在标准中的某处定义?根据构建系统的不同,提及目标文件的顺序可以是任意的,但是,在这样的示例中,它会导致非常不同的程序,并可能导致麻烦的错误。即使我尝试通过添加

从 a.cpp 显式实例化版本
template double foobar<double>(double);

当在链接器列表中的 a.o 之前提到 b.o 时,它不会使来自 a.cpp 的 foobar<> 模板存活。

最佳答案

I know that for templates, there are exceptions to the ODR

模板的 ODR 没有异常(exception),只是模板函数是内联

并且您的程序存在 ODR 违规。
对于常规内联函数,您会遇到类似的问题。

关于c++ - 冲突的模板定义和 ODR,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46340305/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com