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?
Sometimes you want to access global state.
There are a few ways to do so.
static
local variable.extern
variable you reference.static
global variable you reference.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With