Stunt programming. Modern C++ is not about that.

Update: I have added page 4 “User Manual”

Update: I have expanded “Option 2” with a working solution. And hopefully explained why is it very likely, still a stunt.

Stunt programming? Here is one definition. From C2 wiki

Stunt Programming

Doing things the hard or risky way because it is more exciting (and exciting is FUN…until you crash).

I could not agree more with this definition. I have also given a practical example using C#, on the same subject sometimes ago.

Modern C++ provides a LOT of opportunities to engage and get one self-lost in this kind of programming.

(This is one fairly long post with a lot of C++ code inside.  For newcomers to modern C++, but not for beginners. )

Stunt Programming
No this is not me. This is one Stunt Programmer in action.

As we deliver the code we will discuss the findings.

Requirement: provide application-wide storage for a default value of any type. Deliver the functionality to use it, share it and change it by users.

Note: We will provide the bare minimum.  No resilience in presence of multiple threads, no move semantics and no other modern C++ “stunts”.

To make the code a bit more realistic we shall use few enums from the Gdiplus:: namespace.  GDI+ is a well-known artefact to WIN32 aficionados.  To use it one has to place these lines in the header:

And now forward to the …

Solution design

After a shorter think about the requirements we decide we shall provide the following interface to the solution:

The above will return the same predefined default value on repeated calls. And will work over compilation units; it will be global.

To implement this we will use the static value, nested inside a function. Default argument C++ idiom defines the default width. In some later iteration, this might be coming from an external configuration.

Thus we will achieve lazy instantiation and persistence during the program lifetime. Now the task is simple. Implement the above for any type and any name.

Option One

Hot on the plenty of advice by modern advisers on modern C++, our imaginary programmer friend,  tries to “think” as them and quickly produces the skeleton of the template-based function.  After all, classes (so it seems) are not “en vogue” these days. And he seems to remember seeing some quite exciting mixture of modern C++ features on the subject of templates and functions. So here is the first stab at the first option.

Testing

Indeed this looks rather promising. And it compiles too. But there are problems with other code. Here is the one-line problem:

auto default_problem = static_default < REAL, REAL{10} > ;

error C3535: cannot deduce type for 'auto' from 'overloaded-function' error C2440: 'initializing': cannot convert from 'T &(__cdecl *)(const T *)' to 'int' note: Context does not allow for disambiguation of overloaded function above template instance is not "different enough" from two previous ones 

GDI+ Legacy C++ attacks. We try and solve this but things suddenly do not go as smooth as they seem to go when advisers present the same kind of solutions. Alas, not using real-life legacy libraries.

Especially the usage seems troublesome.  We want some clever snippets here. But things do not seem so snazzy all of a sudden.

It seems our modern C++ compiler is “not obeying” when instancing this template :
auto the_problem = static_default < REAL, REAL{10} > ;

Why is this? Why does it produce “int” instead of function pointer on this line and not on the instances elsewhere? Even if we decode that we can not change the GDI+ code, so we will not go there.

Hm. OK, legacy is always a big issue. We know better, and we “take the step back” and take a different path.