Click here to Skip to main content
16,007,760 members
Articles / Programming Languages / C++
Article

Using templates for initialization

Rate me:
Please Sign up or sign in to vote.
3.50/5 (3 votes)
13 Feb 2001 156K   20   38
Use templates to initialize structures or simple member variables.

Introduction

It is quite common in coding to create a structure and then initialize it to all zeros via a memset() [or ZeroMemory()], and in the Microsoft world, it is also quite common to then set a member called cbSize to the sizeof() the structure. All this is very simple, but it can be a bit of a pain in the bum, as well as adding extra lines of code, which always is a bad thing!

Another issue is with simple class member initialization. It is not uncommon to have more than a single constructor. Forgetting to initialize variables in each has caused me problems more than once. Having an initialization function is one solution. I offer another solution.

Template initialization

With a few simple templates, we can rid ourselves of initialization problems!

template <typename T>
struct Clean : public T
{
    Clean()
    {
        ZeroMemory(this, sizeof(T));
    }
};

template <typename T>
struct Sized : public T
{
    Sized()
    {
        this->cbSize = sizeof(T);
    }
};

template <typename T>
struct CleanSized : public T
{
    CleanSized()
    {
        ZeroMemory(this, sizeof(T));
        this->cbSize = sizeof(T);
    }
};

Three templates are presented here to cover the various cases that you would encounter. Clean is if you want your structure to be just zero'd out. Sized is if you only want to set the cbSize member and CleanSized is if you want to do both.

Usage

Instead of specifying the structure directly, you just wrap it with the template. Such as the following:

CleanSized<::SCROLLINFO> scroll_info;
scroll_info.fMask = SIF_POS;
scroll_info.nPos = 20;
::SetScrollInfo(hwnd, SB_VERT, &scroll_info, FALSE);

The first line creates the SCROLLINFO structure, but as it's wrapped by CleanSized, it will zero out the structure, as well as setting the cbSize value to the sizeof(SCROLLINFO). Simple.

You can also use this to express member variables in a class. I.e.:

class CSomeClass
{
    ...
private:
    CleanSized<::SCROLLINFO> m_scroll_info;
};

Then m_scroll_info will be initialized at the same time as the member initialization list (just before entering the constructor).

Now, this is pretty good, we can use this to clean structs in classes, but what about simple types such as int, float, enum, etc?

Well, we cannot use the above templates, as they require deriving from the template type, and as you cannot derive from simple types, this leads us to a new template:

template <typename T>
struct CleanSimple
{
    CleanSimple()
    {
        ZeroMemory(&m_t, sizeof(T));
    }

    T& AsType() {return m_t;}
    operator T&() {return m_t;}
    T* operator&() {return &m_t;}

private:
    CleanSimple(const CleanSimple& rhs);// disallow copy constructor
    operator=(const CleanSimple& rhs); // disallow operator=

    T m_t;
};

Now, you should be able to use this in the same way that you would use the simple type (see note below for an exception). Such as:

class CSomeOtherClass
{
public:
    void SomeFunction()
    {
        ++m_call_count;
        cout << "This function has been called " 
          << m_call_count << " times." << endl;
    }

private:
    CleanSimple<int> m_call_count;
};

(Note: Why the AsType() function? Well, I wish it wasn't there, and I'm not sure if it is a bug in the MS compiler or (as I know the much more likely answer is!) something I'm not thinking of, but in the case of:

CleanSimple<int> x;
int y;
y = x;

you get the following error:

error C2593: 'operator =' is ambiguous

Now, this is a bit strange as, if you change the code to:

CleanSimple<int> x;
unsigned int y;    // or float, short, or another type
y = x;

then it all works fine. Hmmm.)

OK, well this is all good and well, but this sets the variable to zero - what happens if we want to initialize it to some other value other than zero? Time for another template...

template <typename T, T t>
struct InitSimple
{
    InitSimple() : m_t(t) {}

    operator T&() {return m_t;}
    operator T&() const {return m_t;}

    T& AsType() {return m_t;}
    const T& AsType() const {return m_t;}

    T* operator&() {return &m_t;}
    const T* operator&() const {return &m_t;}

    T& operator=(const T& t) {return (m_t = t);}
    InitSimple(const InitSimple& rhs) {m_t = rhs.m_t;}

private:
    T m_t;
};

Now, this template allows you to initialize the type and value where you specify the variable. This means that you can specify in your class prototype, the default values of variables. This means that if you have multiple constructors, you don't have to remember to duplicate all the initialization for all the variables!! (This is a good thing.)

You use the class like this:

class CYetAnotherClass
{
private:
    InitSimple<int, 42> m_atltuae;
    ...
private:
    enum States
    {
        START, RUNNING, STOP
    };

    InitSimple<States, START> m_state;
};

(Note: Not that you would probably want to, but if you defined an InitSimple<> as const, then you MUST have a constructor, otherwise VC++ chokes as it doesn't think it can create a valid constructor because a const variable doesn't appear to have been initialized according to it! [I haven't bothered to check to see if this is mandated by the spec or not.])

Now I only came up with this stuff over the weekend (but who knows, I could have read an article a couple of years ago on this and this stuff finally bubbled to the top - but I don't think so !). So, there could be problems with it. Thus, if you find anything wrong, please give me a yell!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Australia Australia
Born Melbourne, Australia. Mainly C++ developer (my company in Australia is called "SeaPlus Development" but is currently sitting idle). Worked on emergency service systems with Intergraph Public Safety (for New Zealand Police and Fire), on telephony applications for call centres at BP and RMG (both in Melbourne) and on Unified Messager for Avaya (in London). Worked on a casino managment system for International Game Technology (in Las Vegas) and currently working for the National Australia Bank on an equity derivatives product.

Comments and Discussions

 
Generaladd another operator= Pin
TheGreatAndPowerfulOz20-Jul-09 8:39
TheGreatAndPowerfulOz20-Jul-09 8:39 
GeneralProblem using a template class in a structure Pin
arvindb2123-Jul-04 2:21
arvindb2123-Jul-04 2:21 
GeneralMy solution Pin
rrrado23-Jan-03 23:14
rrrado23-Jan-03 23:14 
GeneralRe: My solution Pin
João Paulo Figueira14-Feb-03 6:13
professionalJoão Paulo Figueira14-Feb-03 6:13 
GeneralRe: My solution Pin
Anonymous16-Feb-03 21:08
Anonymous16-Feb-03 21:08 
GeneralRe: My solution Pin
TW25-Feb-04 21:08
TW25-Feb-04 21:08 
GeneralFixed bug in CleanSimple<T> Pin
31-Jan-02 4:20
suss31-Jan-02 4:20 
QuestionA sledgehammer to crack a nut? Pin
Jim Barry21-Nov-00 0:40
Jim Barry21-Nov-00 0:40 
AnswerRe: A sledgehammer to crack a nut? Pin
Paul Westcott21-Nov-00 5:05
Paul Westcott21-Nov-00 5:05 
GeneralRe: A sledgehammer to crack a nut? Pin
Philippe Mori24-Aug-02 12:07
Philippe Mori24-Aug-02 12:07 
This effectivelly makes sence only if done that way...

For classes that are used as it everywhere in code, we should not uses template initialisation since it increase coupling too much... but effectivelly when the class is accessed only through an interface it does not matter much.

In fact, the same thing happens with ATL. There is lot of coupling in a class that implement a bunch of interfaces using ATL (for ex. an ActiveX control) but since the object is accedded through interfaces (and the file is not included anywhere - except for the main object map in ATL 3.0 and before), this should not be a problem.

On the other hand, if good design principles does not means anything to you and you are working on large project, you will have lot of coupling and thus long compilation and link time because every thing get recompiled for every single changes (in large project, it is very easy too have far too much coupling!)

Philippe Mori
GeneralRe: A sledgehammer to crack a nut? Pin
TheGreatAndPowerfulOz20-Jul-09 8:43
TheGreatAndPowerfulOz20-Jul-09 8:43 
AnswerRe: A sledgehammer to crack a nut? Pin
Mr Matt Ellis, Esq24-Nov-00 14:59
Mr Matt Ellis, Esq24-Nov-00 14:59 
GeneralRe: A sledgehammer to crack a nut? Pin
Jim Barry26-Nov-00 23:53
Jim Barry26-Nov-00 23:53 
GeneralRe: A sledgehammer to crack a nut? Pin
Mr Matt Ellis, Esq27-Nov-00 0:15
Mr Matt Ellis, Esq27-Nov-00 0:15 
AnswerRe: A sledgehammer to crack a nut? Pin
19-Feb-01 3:50
suss19-Feb-01 3:50 
GeneralRe: A sledgehammer to crack a nut? Pin
Philippe Mori24-Aug-02 11:56
Philippe Mori24-Aug-02 11:56 
AnswerRe: A sledgehammer to crack a nut? Pin
14-Feb-02 4:27
suss14-Feb-02 4:27 
GeneralVariable names Pin
20-Nov-00 5:00
suss20-Nov-00 5:00 
GeneralRe: Variable names Pin
Michael Dunn20-Nov-00 7:23
sitebuilderMichael Dunn20-Nov-00 7:23 
GeneralRe: Variable names Pin
Paul Westcott20-Nov-00 11:55
Paul Westcott20-Nov-00 11:55 
GeneralRe: Variable names Pin
Philippe Mori24-Aug-02 12:23
Philippe Mori24-Aug-02 12:23 
GeneralAnd not names only. Pin
MarkovAlex10-Jul-03 6:42
MarkovAlex10-Jul-03 6:42 
GeneralI like it, but... Pin
17-Nov-00 4:15
suss17-Nov-00 4:15 
GeneralDangerous with virtual functions Pin
14-Nov-00 22:54
suss14-Nov-00 22:54 
GeneralRe: Dangerous with virtual functions Pin
Paul Westcott15-Nov-00 6:39
Paul Westcott15-Nov-00 6:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.