Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non-type pointer and reference template parameters and how/why they are resolved at compile time. c++

I ask simply why is it allowed to pass the memory location of an object/primitive through a non-type template when I would traditionally expect memory to be allocated and used at runtime. I am aware that the variable whose memory is passed must have external linkage but given that, does that mean the memory locations for externally linked variables are always constant? To illustrate:

template<std::string *temp>
void f();

Wouldn`t the memory location passed through the template vary everytime the program is executed and therefore not be a compile time constant as I thought templates required for non-type arguments?

like image 565
Matias Chara Avatar asked Jul 06 '20 20:07

Matias Chara


1 Answers

This sort of thing is taken care of by fix-ups performed by the runtime loader, the address will indeed vary at runtime, but the location where the address will be found is always at fixed locations with regard to the loaded executable image.

For example the ELF image format (which is very common on *nix these days( has relocation sections which tells the loader where in the program there are values that need to be altered in some way. The compiler and linker together write enough information that the linker is able to generate the final value at run-time.

Say that you have the function:

void Foo::Bar() { }

and then later pass it as a template parameter (very contrived):

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);

Foo::Bar and the instantiation will be found at some particular address in the executable image, the relocations will tell the instantiated do_fn how to call the actual function. And note that the do_fn function name itself doesn't need the run-time address, the name only needs to be calculated in some way that all invoke::do_fn<&Foo::Bar>() calls can resolve to a single specialization (there may be an instantiation from each translation unit but the linker is required to be able to discard all but one under the one-definition rule and it had better be the case that it doesn't matter which instantiation is chosen).

like image 67
SoronelHaetir Avatar answered Oct 31 '22 11:10

SoronelHaetir