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

时间:2011-10-06 03:15:39

标签: c++ function templates linker c++-address

为什么这样做?

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

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++次调用上会产生相同的效果。

我(天真)的理解是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

2 个答案:

答案 0 :(得分:6)

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

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

第5段:

  

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

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

  

如果D的定义满足所有这些要求,则程序的行为应该像D的单一定义一样。

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

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

答案 1 :(得分:4)

这是标准保证的,因为它不违反一个定义规则。实质上,如果内联函数或模板函数的声明和定义在多个转换单元中是相同的,则程序应该表现得就像它有一个定义,它延伸到它的地址。 See my answer to another question that involved static members of template classes.

至于标准[basic.def.odr]的相关部分:

  

......如果D的定义满足所有这些要求,那么   程序应该表现得好像有一个单一的定义D.如果   D的定义不满足这些要求,那么行为   未定义。