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

Option Two


Lambdas! Yes. That divides modern C++ man,  from old C++ boys! We remember the factory pattern and we will use it here too.  Thus showing the unmistakable OO pedigree, too.

We will deliver function template returning a lambda! Close to real stunt, but works And compiler has less problems disambiguating the instances

template<typename T>
inline auto holder_maker(T defval_) {
// no T new_ = defval_ will not compile, try...
return [&](const T * new_ = nullptr)
static T default_value = defval_;
 if (new_ && *new_ != default_value)
    default_value = *new_;
 return default_value;

Looks much more in line with our “c++ ninja” status. Does it not? Very clever little stunt this is. Testing

namespace {
    using namespace Gdiplus;

auto default_smoot = 
auto default_lncap = 
auto default_width = 

Also. The real modern C++ thinking shines through. Functional programming and the rest.  Function pointers are nicely (and obediently by compiler) made. auto is used properly so there are no ugly  pointers to instances of template functions. Or was it function templates?

But. Few little problems here too. First this pesky default argument issue. It seems the good old  argument as “pointer to null” works the best as default argument idiom. It seems it is far from modern C++. We try the “modern” solution on that line:
return [&](const T & new_ = defval_) { ... } 

But alas no can do:

error C2587: 'defval_': illegal use of local variable as default parameter

Oh? That is a bit of a surprise.  We quickly “Google out” for several advice’s but it seems nothing works. Time passes by.  Fine. Is this really a problem?

Well yes it is. If we pass the pointer we need to guarantee it points into the meaningful value. This line is especially troublesome:

default_value = *new_;

We make two big assumptions here: first that de-referencing will produce a meaningful value of type T, and second that operator “=” exists and can take the right hand side as we wish it to.

Hmm. [ps2id id=’update_1′ target=”/]Not entirely sure here. Should we try hard and pull some latest modern C++ tricks here? C++17 guides? Or some yet undiscovered nugget from the stdlib.

And yes we also have noticed this solution does not work as we expect it to. It simply does not return the default value on the first call? Hm. Hm.

Working option Two

Ok, let me jump in here and help to our unfortunate programmer and first provide an C++17 solution. With errors in logic removed too.

As before we will stick to function template returning a lambda . So what do we do to make this behave as we want it to?

On the first call we execute the lambda and return it. Thus on second and all the other calls it will be used with a proper def val from the first call. Again if we try simple  T new_ = defval_  that will not compile.

The elegant  (or is it a stunt?) way around, is to use std::optional

(NOTE : lambda bellow requires T to be a movable type so if T is your class it better be movable)

template<typename T>
inline auto holder_maker(T defval_) {
inner lambda
auto defval_handler 
  = [&](const std::optional<T> & new_ = std::nullopt) 
   -> const T &&
 static T default_value = defval_;
  if (new_ != std::nullopt) {
     T new_val_ = new_.value_or(default_value);
  if (new_val_ != default_value)
    default_value = new_val_ ;
return std::forward<T>( default_value );
     static auto first_call_ = defval_handler();
// on the first call execution will reach here and
// will return the lambda not its result
 return defval_handler; 

Test as before. Yes this is a real modern C++17. std::optional<> and a such. And it works too.  So what could be possibly wrong with it?

The reality is very likely this:

  • Your team/company is still on C++11, or is it C++98?
    • std::optional requires (at least) C++17
  • To your team this code is pretty hard to understand
    • yes this is clever but definitely on the edge of “stunt”
  • To maintain or expand this code  authors presence is required
  • Here insert your favorite show stopper  …

What should we do? We should stop here and think. How would we actually implement this if we focus on the requirements instead  of the latest features possible with the programming language we use. After all if something is in there , in the modern C++, that does not mean we have to use it.

Imperative (in case you forgot) is to solve the requirements. In a feasible manner.