跨编译单元的相同功能模板实例的地址

phs*_*phs 7 c++ linker templates function c++-address

为什么这样做?

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

IH

#ifndef I_H_
#define I_H_

typedef void (*FuncPtr)();

template<typename T>
void FuncTemplate() {}

class C {};

#endif
Run Code Online (Sandbox Code Playgroud)

a.cc

#include "i.h"

FuncPtr a() {
  return &FuncTemplate<C>;
}
Run Code Online (Sandbox Code Playgroud)

b.cc

#include "i.h"

FuncPtr b() {
  return &FuncTemplate<C>;
}
Run Code Online (Sandbox Code Playgroud)

m.cc

#include <iostream>

#include "i.h"

FuncPtr a();
FuncPtr b();

int main() {
  std::cout << (a() == b() ? "equal" : "not equal") << std::endl;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

然后

$ 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
Run Code Online (Sandbox Code Playgroud)

抛到-Wall -Wextra -Werror -ansi所有的g++呼叫产生相同的.

我的(幼稚)理解是FuncTemplate在每个a.ob.o编译单元中实例化一次,因此每个地址应指向一个副本.毕竟这些最终是如何结束的,这种行为是可移植的还是受保护的?

编辑共享库案例:

$ 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
Run Code Online (Sandbox Code Playgroud)

Mar*_*ork 6

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

3.2一个定义规则[basic.def.odr]

第5段:

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

随后必须遵守的标准列表或其未定义的行为.在上面这些确实成立.然后 ...

如果D的定义满足所有这些要求,那么程序应该表现得就像D的单一定义一样.

因此,从技术上讲,您可以在每个翻译单元中获得该功能的副本.

看起来在最后一个短语中的措辞使得它们都要求它们都表现相同.这意味着获取任何这些对象的地址应该产生相同的地址.