6

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?

valentin
  • 175
  • 3
  • 7
  • "Force instantiation:" and "check instantiation" are two rather different things. – n. m. could be an AI May 05 '17 at 07:54
  • Do you want `Initializer` to be created for each instantiation of `Proxy`? E.g. if you create `Proxy` and `Proxy` then `Initializer` will be constructed twice? – Pavel P May 05 '17 at 08:10
  • No, I want only one instance of `Initializer` to be created. I will always inherit from `Proxy`. – valentin May 05 '17 at 08:16
  • Possible duplicate of [How to force a static member to be initialized?](https://stackoverflow.com/questions/6420985/how-to-force-a-static-member-to-be-initialized) – Davis Herring Oct 10 '19 at 06:11

2 Answers2

2

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{};
  • It's better but still requires one extra line of code. If I use the explicit instantiation of `init` its constructor will be executed even if `MyTemplate` is not instantiated. It's not the case. – valentin May 05 '17 at 08:35
2

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.

Pavel P
  • 15,789
  • 11
  • 79
  • 128
  • Oh yes! That's much cleaner. It also saves having to worry about detailed questions about when a template member gets instantiated - which is just the sort of dark corner of the standard that a) developers get confused about; b) *compiler* developers occasionally get confused about. – Martin Bonner supports Monica May 05 '17 at 08:42