跨编译单元的相同函数模板实例化的地址

2022-01-11 00:00:00 function templates linker c++ c++-address

为什么会这样?

我看到类似的 SO 问题表明确实如此,但有人可以更详细地解释一下吗?特别是,这种行为是否受标准保护?

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;
}

然后

$ 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 -ansi 扔到所有 g++ 调用上会产生相同的结果.

Tossing -Wall -Wextra -Werror -ansi onto all the g++ calls produces the same.

我的(天真的)理解是 FuncTemplate 在每个 aobo 编译单元中实例化一次,因此地址应该每个指向一个副本.毕竟这些最终是如何相同的,这种行为是可移植的还是受保护的?

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共享库案例:

$ 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

推荐答案

这包含在一个定义规则中:

This is covered under the one definition rule:

类类型(第 9 条)、枚举类型(7.2)、带有外部链接的内联函数(7.1.2)、类模板(第 14 条)、非静态函数可以有多个定义模板 (14.5.6)、类模板的静态数据成员 (14.5.1.3)、类模板的成员函数 (14.5.1.1) 或未指定某些模板参数的模板特化 (14.7,14.5.5) 在程序中,前提是每个定义出现在不同的翻译单元中,并且定义满足以下要求.给定这样一个名为 D 的实体在多个翻译单元中定义,那么

There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then

有一系列必须遵守的标准或其未定义的行为.在上面这些确实成立.那么……

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 ...

如果 D 的定义满足所有这些要求,那么程序的行为就好像有一个 D 的定义.

If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D.

所以从技术上讲,您可以在每个翻译单元中拥有该函数的副本.

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.

相关文章