【问题标题】:Addresses of identical function template instantiations across compilation units跨编译单元的相同函数模板实例化的地址
【发布时间】:2011-12-01 23:16:48
【问题描述】:

为什么会这样?

我看到类似的 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 编译单元中被实例化一次,因此地址应该每个都指向一个副本。毕竟这些最终是如何相同的,这种行为是可移植的还是受保护的?

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

【问题讨论】:

  • 我会在您的问题中添加“当您用共享库替换目标文件时会发生什么?”。
  • 你有没有在模板函数或类体中尝试过这个?我不认为这会有所作为,但这肯定是一个有趣的结果。我也很好奇如果你将空类C 移动到a.ccb.cc 会发生什么。我认为它会改变结果。
  • @keith.layne 是的,向FuncTemplate 添加琐碎(但取决于模板参数)代码,或向C 添加各种成员不会改变任何东西。至于移动C#include 已经有效地做到了。

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


【解决方案1】:

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

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 的定义。

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

它看起来像最后一个短语中的措辞,但要求它们的行为都相同。这意味着获取这些对象中的任何一个的地址都应该得到相同的地址。

【讨论】:

  • 它稍后指定程序的行为就好像有一个 D 的定义。我相信这会扩展到获取函数的地址。 :)
  • @MSN。我只是在读那个。我现在必须同意你的看法。当我检查的时候。
【解决方案2】:

这是由标准保证的,因为它不违反单一定义规则。本质上,如果一个内联函数或模板函数的声明和定义在多个翻译单元中是相同的,那么程序应该表现得好像它有一个定义,当被采用时,它会扩展到它的地址。 See my answer to another question that involved static members of template classes.

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多