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 practical example using C#, on the same subject sometimes ago.

Modern C++ provides a LOT of opportunity 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 the modern C++, but not for the 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 artifact to WIN32 aficionados.  To use it one has to place these lines in the header:

#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "Gdiplus.lib")

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:

setting up the default to be used elsewhere 
this is global function, it could/should be in a namespace
after this default value is 10, application wide

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

 auto width = default_width() ;

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 external configuration.

inline int default_width ( int new_ = 1 ) {
A single instance is made once and only in the first call
In future iteration we will protect this in presence 
of multiple threads
      static int dflt_ = new_ ;
called with different than default so 
we will change it
          if ( new_ != dflt_ ) dflt_ = new_ ;
in any case return the default value
    return dflt_ ;

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 first option.

emplate< typename T, T defval_ = T() >
inline T & static_default(const T & new_ = defval_ )
static T default_value = defval_;
  if (new_ != default_value)
    default_value =  new_ ;
 return default_value;


namespace {
    using namespace Gdiplus;

const auto sm0 = 
const auto sm1 = 
auto sm2 = static_default<SmoothingMode, SmoothingMode::SmoothingModeAntiAlias>;
auto lc0 = static_default<LineCap, LineCap::LineCapRound>;
auto sm3 = static_default<SmoothingMode>;
auto dlcF = static_default<LineCap>;

auto dlc = dlcF(LineCap::LineCapRound);

Indeed this looks rather promising. It compiles too. But there are problems.

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 

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.

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

As an example it seems compiler is “not obeying” when instancing this template :
auto the_problem = static_default < REAL, REAL{10} > ;

Why is this? Why does it produces “int” instead of function pointer on this line and not on the two instances before it?

Hm. OK. We know better, and we “take the step back” and take the different path.