Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is passing the address of a global variable as a template argument useful?

I recently watched a video from Microsoft explaining some of the new features of C++17 and I was intrigued to find a feature of C++14 (and possibly even prior to that?) which allows you to use the address of a global variable as a constant expression for a template argument.

This allows code like the following:

#include <iostream>
int g_iTest = 5;

template <int* Addr>
struct S {
    static int TestAdd( int iTest ) {
         *Addr = iTest + *Addr;
         return *Addr;
    }
};

int main() {
    S<&g_iTest> s;
    std::cout << s.TestAdd( 5 ) << std::endl;
}

And this will result in an output of 10. As it stands this is an amusing peculiarity of the language to me, however, the guy in the video stressed that this is a useful feature and has been used to reduce code bloat when passing around global variables. However, I don't understand how this works, as surely we could just have a header file with extern int g_iTest and then we can access the global variable without the extra level of abstraction?

What potential use-cases are there for this feature?

like image 639
Thomas Russell Avatar asked Dec 08 '14 11:12

Thomas Russell


1 Answers

Sometimes you want to access global state.

There are a few ways to do so.

  1. You could have a static local variable.
  2. You could have an extern variable you reference.
  3. You could have a static global variable you reference.
  4. You could have callers pass a pointer/reference to the global state in (or function that gets it).
  5. Or you could pass it as a pointer to a global variable in the template argument list.

For each of the above, you can wrap the global state up into a function call, and have the function go get it for you. This just adds a level of indirection. (It also means it is possible to mix two of the above: function passed which uses a static local, or an extern linkage function that within its unit accesses static global state, etc).

What remains to show is that 5 has some advantages over each of the others.

4 requires explicit argument passing, which may cause noise. You may also have constrained signatures do to interop with another API. The fact that the global state is determined at compile time can also lead to some optimizations, and reduce the difficulty of reasoning about what the function does (as the pointer-to-state is one of a fixed set of values determined at compile time).

1 2 and 3 all bind which global state you are using to the code tightly -- the same piece of code cannot use different global state depending on how it is used.

5 allows one piece of code to use global state chosen elsewhere (including multiple different global states). This could allow easier mocking among other things.

A concrete example of this might be a template type or function that stores a pointer to a programmer assigned name. I could write a wrapper around a string-based API that provides me with string-less access to a property in that API by binding the name of the property into a class or function, and then having it consume the API.

like image 189
Yakk - Adam Nevraumont Avatar answered Nov 14 '22 21:11

Yakk - Adam Nevraumont