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

发布于 2024-12-08 13:18:40 字数 1286 浏览 0 评论 0原文

为什么这有效?

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

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 在每个 aobo 编译单元中实例化一次,因此地址应该分别指向一份。这些最终结果是如何相同的,这种行为是可移植的还是受保护的?

编辑共享库案例:

$ 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

陪你到最终 2024-12-15 13:18:40

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

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 的单个定义一样。

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

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

This is covered under the one definition rule:

3.2 One definition rule [basic.def.odr]

Paragraph 5:

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

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.

少女的英雄梦 2024-12-15 13:18:40

这是由标准保证的,因为它不违反单一定义规则。本质上,如果内联函数或模板函数的声明和定义在多个翻译单元中相同,则程序的行为应就像它有一个定义一样,在获取时该定义会扩展到其地址。 请参阅我对涉及模板类静态成员的另一个问题的回答。

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

...如果 D 的定义满足所有这些要求,则
程序的行为应如同 D 仅有一个定义一样。如果
D 的定义不满足这些要求,则行为
未定义。

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]:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文