ValWrapper – a named value wrapper in C++

I recently found myself writing a C++ class where the constructor needed three arguments of type “int”. The arguments where not related so I could not pass them as a color, point3d or something similar.

The class looked like this

struct AnimationConfig {
 public:
  AnimationConfig(int numFrames, int frameDelay, int numAnimations)
        : numFrames(numFrames),
          frameDelay(frameDelay),
          numAnimations(numAnimations) {
    }

    int numFrames;
    int frameDelay;
    int numAnimations;
};

and an instance could be created in this way

AnimationConfig aniConfig(5, 100, 3);

This code looks horrible. What is 5, 100 and 3? The code could be improved by adding constants or helper variables like this

const auto numFrames = 5;
const auto frameDelay = 100;
const auto numAnimations = 3;
AnimationConfig aniConfig(numFrames, frameDelay, numAnimations);

This is okay for a single instance, but what if we need to create several instances? This would require a lot of variables. Another option would be to create an uninitialized instance and assign each member implicitly. The is just as verbose as the previous alternative and there is a risk that the user forgets to initialize a certain member.

I thought for a while and then I came up with that I consider to be a much better alternative – a ValWrapper class. The idea is that we create a new class that is named after the parameter that we wish to pass. Its constructor is marked as “explicit” so you need to cast the value you are passing (this is actually a feature) and you must initialize each such variable.

#pragma once
template <typename T> struct ValWrapper {
    explicit ValWrapper(T value) : mValue(value) {
    }
    operator T() const {
        return mValue;
    }
  private:
    T mValue;
};

#define DECL_VALWRAPPER(name, realtype)                 \
    class name : public ValWrapper<realtype> {          \
        using ValWrapper<realtype>::ValWrapper;         \
    };

How would AnimationConfig look if it used ValWrapper? It would look this way

struct AnimationConfig {
  public:
    DECL_VALWRAPPER(NumFrames, size_t);
    DECL_VALWRAPPER(FrameDelayMs, size_t)
    DECL_VALWRAPPER(NumAnimations, size_t);
    
    AnimationConfig(NumFrames numFrames, 
                    FrameDelayMs frameDelay,
                    NumAnimations numAnimations)
        : numFrames(numFrames),
          frameDelay(frameDelay),
          numAnimations(numAnimations) {
    }

    NumFrames numFrames;
    FrameDelayMs frameDelay;
    NumAnimations numAnimations;
};

Now it is no longer possible to construct an AnimationConfig as follows.

AnimationConfig aniConfig(5, 100, 3);

Instead you need to create it this way

Aniconfig aniconfig(AnimationConfig::NumFrames(5),
                    AnimationConfig::FrameDelayMs(100),
                    AnimationConfig::NumAnimations(3));

I consider this to be much more readable. Since ValWrapper is a template it can work with any type, not just integers.

 

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s