/***************************************************************************
- * Copyright (C) 2005-2018 by the Quassel Project *
+ * Copyright (C) 2005-2020 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#pragma once
-#include <QtGlobal>
+#include <iostream>
+
+// For Windows DLLs, we must not export the template function.
+// For other systems, we must, otherwise the local static variables won't work across library boundaries...
+#ifndef Q_OS_WIN
+# include "common-export.h"
+# define QUASSEL_SINGLETON_EXPORT COMMON_EXPORT
+#else
+# define QUASSEL_SINGLETON_EXPORT
+#endif
+
+namespace detail {
+
+// This needs to be a free function instead of a member function of Singleton, because
+// - MSVC can't deal with static attributes in an exported template class
+// - Clang produces weird and unreliable results for local static variables in static member functions
+//
+// We need to export the function on anything not using Windows DLLs, otherwise local static members don't
+// work across library boundaries.
+template<typename T>
+QUASSEL_SINGLETON_EXPORT T* getOrSetInstance(T* instance = nullptr, bool destroyed = false)
+{
+ static T* _instance = instance;
+ static bool _destroyed = destroyed;
+
+ if (destroyed) {
+ _destroyed = true;
+ return _instance = nullptr;
+ }
+ if (instance) {
+ if (_destroyed) {
+ std::cerr << "Trying to reinstantiate a destroyed singleton, this must not happen!\n";
+ abort(); // This produces a backtrace, which is highly useful for finding the culprit
+ }
+ if (_instance != instance) {
+ std::cerr << "Trying to reinstantiate a singleton that is already instantiated, this must not happen!\n";
+ abort();
+ }
+ }
+ if (!_instance) {
+ std::cerr << "Trying to access a singleton that has not been instantiated yet!\n";
+ abort();
+ }
+ return _instance;
+}
+
+} // detail
/**
* Mixin class for "pseudo" singletons.
*
* @param instance Pointer to the instance being created, i.e. the 'this' pointer of the parent class
*/
- Singleton(T *instance)
+ Singleton(T* instance)
{
- if (_destroyed) {
- qFatal("Trying to reinstantiate a destroyed singleton, this must not happen!");
- abort(); // This produces a backtrace, which is highly useful for finding the culprit
- }
- if (_instance) {
- qFatal("Trying to reinstantiate a singleton that is already instantiated, this must not happen!");
- abort();
- }
- _instance = instance;
+ detail::getOrSetInstance<T>(instance);
}
// Satisfy Rule of Five
- Singleton(const Singleton &) = delete;
- Singleton(Singleton &&) = delete;
- Singleton &operator=(const Singleton &) = delete;
- Singleton &operator=(Singleton &&) = delete;
+ Singleton(const Singleton&) = delete;
+ Singleton(Singleton&&) = delete;
+ Singleton& operator=(const Singleton&) = delete;
+ Singleton& operator=(Singleton&&) = delete;
/**
* Destructor.
*/
~Singleton()
{
- _instance = nullptr;
- _destroyed = true;
+ detail::getOrSetInstance<T>(nullptr, true);
}
/**
*
* @returns A pointer to the instance
*/
- static T *instance()
+ static T* instance()
{
- if (_instance) {
- return _instance;
- }
- qFatal("Trying to access a singleton that has not been instantiated yet");
- abort();
+ return detail::getOrSetInstance<T>();
}
-
-private:
- static T *_instance;
- static bool _destroyed;
-
};
-
-template<typename T>
-T *Singleton<T>::_instance{nullptr};
-
-template<typename T>
-bool Singleton<T>::_destroyed{false};