Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force template static member instantiation

I'm trying to create the program that executes some code only if the template is instantiated (it will be used for low-level driver initialization). Now I have the following solution.

class Initializer
{
public:
    Initializer(){
        // This code is executed once
    }

    void silly() const{

    }
};

template <class T>
class Proxy{
protected:
    static const Initializer init;
};

template<class T>
const Initializer Proxy<T>::init;

template<class T>
class MyTemplate : public Proxy<void>{
public:
    static void myMethod1(){
        init.silly();

        // ... Something useful
    }

    static void myMethod2(){
        init.silly();

        // ... Something useful
    }
};

The Initializer default constructor is executed only in case I call myMethod1() or myMethod2() somewhere.

But is there a way to get rid of those init.silly(); lines?

like image 934
valentin Avatar asked May 05 '17 07:05

valentin


2 Answers

Your problem, is that members of a template are not instantiated unless they are referenced.

Rather than calling init.silly(), you can just reference the member:

    static void myMethod1(){
        (void)init;

        // ... Something useful
    }

Or, if you want init to be defined absolutely always, you can explicitly instantiate it:

template<>
const Initializer Proxy<void>::init{};
like image 174
Martin Bonner supports Monica Avatar answered Sep 28 '22 06:09

Martin Bonner supports Monica


template and low-level driver initialization?.. I'd try to make it as C as possible :) to ensure exact behavior.

You can do something like this perhaps:

class Initializer
{
public:
    Initializer() {
        // This code is executed once
    }
};

template <class T>
class Proxy {
protected:
    Proxy()
    {
        static Initializer init;
    }
};

template<class T>
class MyTemplate : public Proxy<void> {
public:
    void myMethod1() {
        // ... Something useful
    }

    void myMethod2() {
        // ... Something useful
    }
};

All your code uses only static functions and doesn't really show why you would use classes and templates. With my change I made myMethod1 and myMethod2 non static and Proxy() constructor would create Initializer once.

Note that because of all that template mess your Initializer might be executed as many times as you instantiate Proxy template. Did you really mean it? If not, convert to clear readable code that doesn't have this unexpected results. This will also be better maintainable and readable for others:

class Initializer
{
    Initializer() {
        // This code is executed once
    }
public:
    void init()
    {
        static Initializer init;
    }
};


template<class T>
class MyTemplate {
public:
    static void myMethod1() {
        Initializer::init();
        // ... Something useful
    }

    static void myMethod2() {
        Initializer::init();
        // ... Something useful
    }
};

This makes it absolutely clear that Initializer will be created only once just before myMethod1 or myMethod2 is called. If nothing calls your Initializer::init then that code from Initializer should be removed at link time.

like image 22
Pavel P Avatar answered Sep 28 '22 06:09

Pavel P