非类型指针和引用模板参数以及它们在编译时如何/为什么被解析。C++

Mat*_*ara 8 c++ linker templates

我只是问为什么当我传统上希望在运行时分配和使用内存时,为什么允许通过非类型模板传递对象/原语的内存位置。我知道传递其内存的变量必须具有外部链接,但鉴于此,这是否意味着外部链接变量的内存位置始终不变?为了显示:

template<std::string *temp>
void f();
Run Code Online (Sandbox Code Playgroud)

每次执行程序时,通过模板传递的内存位置会不会有所不同,因此不会像我认为非类型参数所需的模板那样是编译时常量?

Sor*_*tir 5

这类事情由运行时加载程序执行的修复来处理,地址确实会在运行时变化,但地址所在的位置总是在与加载的可执行映像相关的固定位置。

例如,ELF 图像格式(现在在 *nix 上非常常见(具有重定位部分,它告诉加载程序在程序中哪些值需要以某种方式进行更改。编译器和链接器一起写入足够的信息,以便链接器能够在运行时生成最终值。

说你有这个功能:

void Foo::Bar() { }
Run Code Online (Sandbox Code Playgroud)

然后将其作为模板参数传递(非常做作):

template<typename Class>
struct invoke {
  template<void (Class::*Fn)()>
  void do_fn(Class * ptr ) { (ptr->*Fn)(); }
};
..
Foo f;
invoke<Foo>::do_fn<&Foo::Bar>(&f);
Run Code Online (Sandbox Code Playgroud)

Foo::Bar 和实例化将在可执行映像中的某个特定地址处找到,重定位将告诉实例化的 do_fn 如何调用实际函数。并注意 do_fn 函数名本身不需要运行时地址,该名称只需要以某种方式计算,所有 invoke::do_fn<&Foo::Bar>() 调用都可以解析为单个特化(每个翻译单元可能有一个实例化,但要求链接器能够在一个定义规则下丢弃除一个之外的所有实例,最好是选择哪个实例化无关紧要)。