R.M. R.M. - 2 months ago 13
C++ Question

How to fix a purported lack of an "explicit instantiation declaration" when compiling a CRTP Singleton with Clang?

We're using the curiously recurring template pattern to implement singletons. However, with recent Clang versions we're getting a -Wundefined-var-template warning. The suggested fix to which is to add an "explicit instantiation declaration".

I attempted to do this, but then I get errors about "explicit specialization after instantiation" in the compilation unit where the definition of the singleton template class member variable is.

What's the appropriate construct to fix the issue highlighted by this warning?




Simplified Details (much of the logic has been removed, to make a MCVE):

SingletonBase.hh:

template < class T > class SingletonBase {
public:
static T * get_instance() {
if ( ! instance_ ) {
instance_ = T::create_singleton_instance();
}
return instance_;
}
private:
static T * instance_;
};


Singleton.hh:

#include "SingletonBase.hh"

class Singleton : public SingletonBase< Singleton > {
friend class SingletonBase< Singleton >;
public:
int do_stuff(int v) { return v+2; }
private:
static Singleton * create_singleton_instance() {
return new Singleton;
}
};


Singleton.cc:

#include "Singleton.hh"
template <> Singleton * SingletonBase< Singleton >::instance_( nullptr );


When we compile with a recent version of clang (3.9.0; but not with clang 3.7), we get an warning when compiling files other than Singleton.cc. (with -std=c++11 and -Werror)

In file included from OtherFile.cc:2:
In file included from ./Singleton.hh:2:
./SingletonBase.hh:5:16: warning: instantiation of variable 'SingletonBase<Singleton>::instance_' required here, but no definition is available [-Wundefined-var-template]
if ( ! instance_ ) {
^
OtherFile.cc:5:25: note: in instantiation of member function 'SingletonBase<Singleton>::get_instance' requested here
return Singleton::get_instance()->do_stuff(4);
^
./SingletonBase.hh:11:18: note: forward declaration of template entity is here
static T * instance_;
^

./SingletonBase.hh:5:16: note: add an explicit instantiation declaration to suppress this warning if 'SingletonBase<Singleton>::instance_' is explicitly instantiated in another translation unit
if ( ! instance_ ) {
^
1 error generated.


I added the following line to the end of Singleton.hh, as it's what I'm lead to believe the explicit instantiation declaration syntax should be.

extern template Singleton* SingletonBase< class Singleton >::instance_;


While that fixes issues with compiling OtherFile.cc, it results in a new error when compiling Singleton.cc

Singleton.cc:3:57: error: explicit specialization of 'instance_' after instantiation
template <> Singleton * SingletonBase< Singleton >::instance_( nullptr );
^
./Singleton.hh:14:66: note: explicit instantiation first required here
extern template Singleton* SingletonBase< class Singleton >::instance_;
^
1 error generated.


What should I be doing here to fix these warnings/errors? Is there a more appropriate syntax for the explicit instantiation declaration that I'm not understanding?

Answer

I would recommend this implementation of a singleton instead:

template<class T>
struct SingletonBase {
    static T& get_instance() {
        static T instance;
        return instance;
    }
};

It's thread safe and remove your warning.

If you want, you can keep your create_singleton_instance:

template<class T>
struct SingletonBase {
    static T& get_instance() {
        static T instance{T::create_singleton_instance()};
        return instance;
    }
};

And changing the function implementation to:

static SomeClass create_singleton_instance() {
    return {};
}
Comments