Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is correct way to initialize a static member of type 'T &' in a templated class?

I'm playing around with an eager-initializing generic singleton class. The idea is that you inherit publicly from the class like so:

class foo : public singleton<foo> { };

I've learned a lot in the process but I'm stuck right now because it's breaking my Visual Studio 2008 linker. The problem is with the static instance member and/or its initialization.

template<class T>
class singleton {
    singleton();
    singleton(singleton const &);
    singleton & operator = (singleton const &);
public:
    static T & instance;
};
template<class T> T & T::instance;

Any insight would be greatly appreciated!

EDIT:

With this class declaration...

template<class T>
class singleton {
    singleton();
    singleton(singleton const &);
    singleton & operator = (singleton const &);
public:
    static T instance;
};
template <class T> T singleton<T>::instance;

When I try to do this...

class foo : public singleton<foo> { };

I get this error...

error C2248: 'singleton::singleton' : cannot access private member declared in class 'singleton'

...

This diagnostic occurred in the compiler generated function 'foo::foo(void)'

My interpretation is that singleton wants to construct a foo object which, by inheritance, depends on the construction of a singleton whose constructor is private. I figured singleton would have access to its own constructor but I guess not. Any ideas?

EDIT 2:

I've realized that the approach of inheriting from singleton<T> has the problem of requiring change to the class to be used as a singleton. I've ended up with the following code for my eager-initializing singleton class template.

template<typename T>
class singleton_wrapper {
    singleton_wrapper();
    singleton_wrapper(singleton_wrapper const &);
    singleton_wrapper & operator = (singleton_wrapper const &);
    static T instance;
    template<typename T> friend T & singleton();
};
template<typename T> T singleton_wrapper<T>::instance;

template<typename T>
T & singleton() {
    return singleton_wrapper<T>::instance;
}

For class...

class foo {
public:
    void bar() { }
};

...One would access a single instance of it (initialized before main()) using the following:

singleton<foo>().bar();

Thanks again for the help, especially GMan. I'm very pleased with my first experience on stackoverflow.

like image 518
Nick Strupat Avatar asked Feb 28 '23 18:02

Nick Strupat


1 Answers

You can't, since you don't have a concrete instance. You can need to create an actual instance that you can refer to:

template <class T>
class singleton {
    ...
private:
    static T instance_;
public:
    static T& instance;
};
template <class T> T singleton<T>::instance_;
template <class T> T& singleton<T>::instance = singleton<T>::instance;

Or, more simply, just ditch the reference altogether:

template <class T>
class singleton {
    ...
public:
    static T instance;
};
template <class T> T singleton<T>::instance;
like image 137
Adam Rosenfield Avatar answered Mar 02 '23 07:03

Adam Rosenfield