跨编译单元的相同函数模板实例化的地址
为什么这有效?
我看到类似的问题说明确实如此,但有人可以更详细地解释一下吗?特别是,这种行为是否受到标准保护?
ih
#ifndef I_H_
#define I_H_
typedef void (*FuncPtr)();
template<typename T>
void FuncTemplate() {}
class C {};
#endif
a.cc
#include "i.h"
FuncPtr a() {
return &FuncTemplate<C>;
}
b.cc
#include "i.h"
FuncPtr b() {
return &FuncTemplate<C>;
}
m.cc
#include <iostream>
#include "i.h"
FuncPtr a();
FuncPtr b();
int main() {
std::cout << (a() == b() ? "equal" : "not equal") << std::endl;
return 0;
}
然后
$ g++ -c -o a.o a.cc
$ g++ -c -o b.o b.cc
$ g++ -c -o m.o m.cc
$ g++ a.o b.o m.o -o prog
$ ./prog
equal
扔-Wall -Wextra -Werror -所有
都会产生相同的结果。g++
调用上的 ansi
我(天真的)理解是,FuncTemplate
在每个 ao
和 bo
编译单元中实例化一次,因此地址应该分别指向一份。这些最终结果是如何相同的,这种行为是可移植的还是受保护的?
编辑共享库案例:
$ g++ -shared -o liba.so a.cc
$ g++ -shared -o libb.so b.cc
$ g++ -c -o m.o m.cc
$ g++ -L. -la -lb m.o -o prog
$ ./prog
equal
Why does this work?
I see similar SO questions stating that it does, but could someone explain it in more detail? Particularly, is this behavior protected by a standard?
i.h
#ifndef I_H_
#define I_H_
typedef void (*FuncPtr)();
template<typename T>
void FuncTemplate() {}
class C {};
#endif
a.cc
#include "i.h"
FuncPtr a() {
return &FuncTemplate<C>;
}
b.cc
#include "i.h"
FuncPtr b() {
return &FuncTemplate<C>;
}
m.cc
#include <iostream>
#include "i.h"
FuncPtr a();
FuncPtr b();
int main() {
std::cout << (a() == b() ? "equal" : "not equal") << std::endl;
return 0;
}
Then
$ g++ -c -o a.o a.cc
$ g++ -c -o b.o b.cc
$ g++ -c -o m.o m.cc
$ g++ a.o b.o m.o -o prog
$ ./prog
equal
Tossing -Wall -Wextra -Werror -ansi
onto all the g++
calls produces the same.
My (naive) understanding is that FuncTemplate
is instantiated once in each of the a.o
and b.o
compilation units, and so the addresses should each point to one copy. How do these end up the same after all, and is this behavior portable or protected?
EDIT The shared library case:
$ g++ -shared -o liba.so a.cc
$ g++ -shared -o libb.so b.cc
$ g++ -c -o m.o m.cc
$ g++ -L. -la -lb m.o -o prog
$ ./prog
equal
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这包含在单一定义规则中:
3.2 单一定义规则 [basic.def.odr]
第 5 段:
有一整套必须遵循的标准或其未定义的行为。在上面这些确实成立。然后 ...
因此从技术上讲,您可以在每个翻译单元中拥有该函数的副本。
看起来像最后一个短语中的措辞,但要求它们的行为都相同。这意味着获取这些对象中任何一个的地址都应该得到相同的地址。
This is covered under the one definition rule:
3.2 One definition rule [basic.def.odr]
Paragraph 5:
There is a whole list of criteria that follow that have to be-adhered to or its undefined behavior. In the above these do hold. Then ...
So technically you can have a copy of the function in each translation unit.
It looks like the wording in the last phrase though makes it a requirement that they all behave the same. This means taking the address of any of these objects should result in the same address.
这是由标准保证的,因为它不违反单一定义规则。本质上,如果内联函数或模板函数的声明和定义在多个翻译单元中相同,则程序的行为应就像它有一个定义一样,在获取时该定义会扩展到其地址。 请参阅我对涉及模板类静态成员的另一个问题的回答。
标准
[basic.def.odr]
的相关部分:This is guaranteed by the standard as it does not violate the one definition rule. In essence, if the declaration and definition of an inline function or template function is the same in multiple translation units, the program shall behave as though there is one definition of it, which extends to its address, when taken. See my answer to another question that involved static members of template classes.
As for the relevant section of the standard
[basic.def.odr]
: