If I access a singleton in an executable that is linked a shared library and then access the same singleton within the shared library, two instances are created.
Is this not allowed or am I doing something wrong?
Here is some code to illustrate. I create a shared library containing Singleton.h, Manager.h, Window.h, Window.cpp, and DeclSpec.h
Singleton template class:
#ifndef SINGLETON_H
#define SINGLETON_H
#include <memory>
#include <iostream>
template <typename T>
class Singleton
{
private:
static std::unique_ptr<T> s_instance;
public:
static T &instance()
{
if (!s_instance) {
std::cout << "Creating..." << std::endl;
s_instance = std::make_unique<T>();
}
return *s_instance;
}
};
template <typename T>
std::unique_ptr<T> Singleton<T>::s_instance;
#endif //SINGLETON_H
I create a manager class that is a singleton:
#ifndef MANAGER_H
#define MANAGER_H
#include "Singleton.h"
class Manager : public Singleton<Manager>
{
};
#endif //MANAGER_H
Then I have a window class within the same library that uses the manager.
Here is the h (DECLSPEC is defined in DeclSpec.h and handles library export/import):
#ifndef WINDOW_H
#define WINDOW_H
#include "DeclSpec.h"
class DECLSPEC Window
{
public:
Window();
};
#endif //WINDOW_H
Here is the cpp:
#include "Manager.h"
#include "Window.h"
Window::Window()
{
Manager &m = Manager::instance();
}
Finally, I create an executable that is linked to the above shared library with a simple main.cpp:
#include "Manager.h"
#include "Window.h"
int main(void)
{
Manager &m = Manager::instance();
Window w;
return 0;
}
The output:
Creating...
Creating...
The singleton is created twice.
Any pointers?
Just like with any other class, you need to tell the compiler to either export or import the template class specialization. Here is how to properly declare your template specialization as import or export.
#ifndef MANAGER_H
#define MANAGER_H
#include "Singleton.h"
// <BEGIN modifications>
// forward declare the Manager class
class Manager;
// delcare your specialization as import or export
// NOTE: this only works on win32.
// For other platforms you would use the 'extern' keyword, and it does not go in the same place as DECLSPEC
template class DECLSPEC Singleton<Manager>;
// <END modifications>
class Manager : public Singleton<Manager>
{
};
#endif //MANAGER_H
The goal here is to tag the specific specialization of Singleton with DECLSPEC. We dont want to tag the template class itself because you may want to have singletons of other types that dont live in your main executable.
The microsoft compiler will not implement the templates tagged with a declspec. Other compilers (clang, gcc) use the 'extern' keyword for this purpose. So you are responsible for explicitly instantiating the template in one of your cpp files. If you forget to do this, you will get linker errors just like you had made a class member function and forgot to implement it.
Conversely, if you forget to reference Singleton somewhere in your code without the DECLSPEC (like if you forward declare the class), you will get 'multiple symbols defined' linker errors.
So add the following to your Manager.cpp to force the compiler to fully instantiate the template specialization of your Singleton:
template class Singleton<Manager>;
Related
So I have a dll which exports class which is derived from an explicitly instantiated (also exported) template.
parent.hpp
#pragma once
template <typename T>
struct parent {
parent(T t) m_t(t) {};
void print();
T m_t;
};
parent.cpp
template<typename T>
void parent<T>::print() {
cout << m_t << endl;
}
template class LIB_API parent<int>;
child.hpp
#include "parent.hpp"
extern template class parent<int>;
struct LIB_API child : public parent<int> {
using parent<int>::parent;
void some_method();
}
child.cpp defines some_method
So far everything is great and works. I can safely use the child class from targets which link with the dll. The problem comes when I use the child class in the dll itself in another compilation unit:
some_other_dll_file.cpp:
void func()
{
child c(53);
c.print();
c.some_method();
}
In this case I get a warning: warning C4661: 'void parent<int>::print(void)': no suitable definition provided for explicit template instantiation request
(or in my particular case a ton of warnings for each and every method which is not visible in the template header in each and every file in the dll which uses the child class)
Note that it's a warning only. Eventually everything compiles and links, and works fine.
Is there a way to change the code so I don't get this warning?
The code contains lots of errors, probably some are typos, some others are missing parts of code, and so on.
The warning you get is because the explicitly instantiated template (parent<int>) doesn't have the print method defined (only declared) in the some_other_dll_file translation unit. Check [SO]: warning C4661:no suitable definition provided for explicit template instantiation request (#SergeBallesta's answer). You'll get rid of the warning by moving print's body in parent.hpp.
Below it's a working example.
Dll project
dll00.h:
#pragma once
#if defined (DLL00_INTERNAL) || defined(DLL00_STATIC)
# define DLL00_API
#else
# if defined(DLL00_EXPORTS)
# define DLL00_API __declspec(dllexport)
# else
# define DLL00_API __declspec(dllimport)
# endif
#endif
parent.hpp:
#pragma once
#include <dll00.h>
#include <iostream>
template <typename T>
class parent {
public:
parent(T t): m_t(t) {};
void print();
private:
T m_t;
};
template <typename T>
void parent<T>::print() {
std::cout << m_t << std::endl;
}
parent.cpp:
#define DLL00_EXPORTS
#include <parent.hpp>
template class DLL00_API parent<int>;
child.hpp:
#pragma once
#include <dll00.h>
#include <parent.hpp>
extern template class parent<int>;
class DLL00_API child : public parent<int> {
public:
using parent<int>::parent;
void some_method();
};
child.cpp:
#define DLL00_EXPORTS
#include <child.hpp>
#include <iostream>
void child::some_method() {
std::cout << "child::some_method" << std::endl;
}
other.cpp:
#define DLL00_INTERNAL
#include <child.hpp>
void func() {
//*
child c(53);
c.print();
c.some_method();
//*/
}
App project
main.cpp:
#include <child.hpp>
int main() {
child c(12);
c.print();
c.some_method();
return 0;
}
If for some reason you want to have the function body in parent.cpp, then you'll have to simply ignore the warning. If you don't want to see it, add #pragma warning(disable: 4661) at parent.hpp's beginning. But bear in mind that ignoring warnings might get you in trouble in some cases.
I'm using the CRTP pattern to create an interface, which other classes will derive from.
In the interface I forward declare a structure (important because I don't want to drag other stuff in the interface), but I include its definition in the cpp file which defines the interface.
Interface.h
#ifndef INTERFACE_H_INCLUDED
#define INTERFACE_H_INCLUDED
// forward declaration
class ForwardDecl;
template <class Derived>
class Interface
{
public:
ForwardDecl interfaceMethod();
};
#endif // INTERFACE_H_INCLUDED
ForwardDecl.h
#ifndef FORWARDDECL_H_INCLUDED
#define FORWARDDECL_H_INCLUDED
struct ForwardDecl
{
ForwardDecl(int i):internal(i)
{}
int internal;
};
#endif // FORWARDDECL_H_INCLUDED
Interface.cpp
#include "Interface.h"
#include "ForwardDecl.h"
template<class Derived>
ForwardDecl Interface<Derived>::interfaceMethod()
{
return static_cast<Derived *>(this)->implementation_func();
}
And this is the implementation which implements the interface
Implementation.h
#ifndef IMPLEMENTATION_H_INCLUDED
#define IMPLEMENTATION_H_INCLUDED
#include "Interface.h"
class ForwardDecl;
class Implementation: public Interface<Implementation>
{
friend class Interface<Implementation>;
private:
ForwardDecl implementation_func();
};
#endif // IMPLEMENTATION_H_INCLUDED
Implementation.cpp
#include "Implementation.h"
#include "ForwardDecl.h"
#include <iostream>
struct ForwardDecl Implementation::implementation_func()
{
ForwardDecl fd(42);
std::cout << fd.internal << std::endl;
return fd;
}
And the main file
#include <iostream>
#include "Implementation.h"
#include "ForwardDecl.h"
using namespace std;
int main()
{
Implementation impl;
ForwardDecl fd = impl.interfaceMethod();
cout << fd.internal << endl;
return 0;
}
I get linking errors on both VS and GCC.
Any workaround? Thank you.
There is a flaw in your very approach: You have a public function returning a ForwardDecl instance, so every client wanting to use this function also must include the according definition of that type, which implies you can make that type public from the beginning. This includes making the function definition inline, which will fix your linker problems.
However, if you really want to hide the content of that structure and you are sure clients don't need it directly, you can declare it and then pass around references to such a structure (or pointers, but raw pointers are evil albeit not in the same league of evil as #macros). In that case, I would still make the function definition inline.
If you really, really want to not make the function inline, you can also explicitly instantiate the function template for the types that you need. You would add at the end of the template's .cpp file something like template class Interface<int>; (I don't remember the exact syntax so take that with a few flakes of fleur de sel, check out the C++ FAQ at parashift.com for more info). This makes the template a little less universal though, as it requires adjustments for any type that you want to use it with, but it can be an approach in some corner cases.
The definitions of function templates and member functions of class templates need to be visible in all translation units that instantiate those templates. That is, you shouldn't put template definitions in a .cpp file, which means you need to move the contents of Interface.cpp up into Interface.h.
If I'm creating a static library with a header file such as this:
// Myfile.h
#include "SomeHeaderFile.h" // External library
Class MyClass
{
// My code
};
Within my own project I can tell the compiler (in my case, Visual Studio) where to look for SomeHeaderFile.h. However, I don't want my users to be concerned with this - they should be able to include my header without having to inform their compiler about the location of SomeHeaderFile.h.
How is this type of situation normally handled?
This is a classic "compilation firewall" scenario. There are two simple solutions to do:
Forward-declare any classes or functions that you need from the external library. And then include the external library's header file only within your cpp file (when you actually need to use the classes or functions that you forward-declared in your header).
Use the PImpl idiom (or Cheshire Cat) where you forward-declare an "implementation" class that you declare and define only privately (in the cpp file). You use that private class to put all the external-library-dependent code to avoid having any traces of it in your public class (the one declared in your header file).
Here is an example using the first option:
#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H
class some_external_class; // forward-declare external dependency.
class my_class {
public:
// ...
void someFunction(some_external_class& aRef); // declare members using the forward-declared incomplete type.
};
#endif
// in the cpp file:
#include "my_header.h"
#include "some_external_header.h"
void my_class::someFunction(some_external_class& aRef) {
// here, you can use all that you want from some_external_class.
};
Here is an example of option 2:
#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H
class my_class_impl; // forward-declare private "implementation" class.
class my_class {
private:
std::unique_ptr<my_class_impl> pimpl; // a vanishing facade...
public:
// ...
};
#endif
// in the cpp file:
#include "my_header.h"
#include "some_external_header.h"
class my_class_impl {
private:
some_external_class obj;
// ...
public:
// some functions ...
};
my_class::my_class() : pimpl(new my_class_impl()) { };
Say the external header file contains the following:
external.h
class foo
{
public:
foo();
};
And in your library you use foo:
myheader.h:
#include "external.h"
class bar
{
...
private:
foo* _x;
};
To get your code to compile, all you have to do is to forward declare the foo class (after that you can remove the include):
class foo;
class bar
{
...
private:
foo* _x;
};
You would then have to include external.h in your source file.
I get linker errors when compiling the following code:
Here the header file:
// Solver.h
#ifndef SOLVER_H_
#define SOLVER_H_
#include <vector>
#include "Resource.h"
#include "ValueFunction.h"
template<typename T>
class Solver {
public:
Solver(std::vector<Resource>& resources);
private:
std::vector<T> valfuncs;
};
#endif /* SOLVER_H_ */
And here the source file:
// Solver.cpp
#include "Solver.h"
template<typename T>
Solver<T>::Solver(std::vector<Resource>& resources) :
valfuncs(resources.size()) {}
// Explicit class declaration
template class Solver<ValueFunction>;
And the call:
// openadp.cpp
#include "Solver.h"
int main(int argc, char *argv[]) {
std::vector<Resource> resources(4);
Solver<ValueFunction> sol(resources);
return 0;
}
The code is compiling fine if I remove valfuncs(resources.size()) from the initialization list. Why is it not possible to initialize the vector with the class passed from my template list?
Thanks in advance,
Reza
Update
Sorry, but this mini-example does not reproduce the error!
I'm trying to find one which does.
Update 2
The linker error was due to a wrong order of includes in my cmake files.
Remark
This question is not a duplicate of Why can templates only be implemented in the header file? first, because (the most obvious) the code compiles and second, there is an implicite instantiation of the Solver template: template class Solver<ValueFunction>;, thus the compiler is aware of an instance of the defined type.
I am trying to implement an observer pattern with a template subject class. The observers don't (need to) know the subjects type, so I made an interface for the attach method without this type. This is my implementation:
SubjectInterface.h
#ifndef SUBJECTINTERFACE_H_
#define SUBJECTINTERFACE_H_
#include <list>
#include "Observer.h"
// Template-independant interface for registering observers
class SubjectInterface
{
public:
virtual void Attach(Observer*) = 0;
}; // class SubjectInterface
#endif // SUBJECTINTERFACE_H_
Subject.h
#ifndef SUBJECT_H_
#define SUBJECT_H_
#include <list>
#include "Observer.h"
#include "SubjectInterface.h"
template <class T>
class Subject : public SubjectInterface
{
public:
Subject();
~Subject();
void Attach(Observer*);
private:
T mValue;
std::list<Observer*> mObservers;
}; // class Subject
#include "Subject.cpp"
#endif // SUBJECT_H_
Subject.cpp
template <class T>
Subject<T>::Subject()
{
}
template <class T>
Subject<T>::~Subject()
{
}
template <class T>
void Subject<T>::Attach(Observer* test)
{
mObservers.push_back(test);
}
Observer.h
#ifndef OBSERVER_H_
#define OBSERVER_H_
#include "SubjectInterface.h"
#include <iostream>
class Observer
{
public:
Observer(SubjectInterface* Master);
virtual ~Observer();
private:
SubjectInterface* mMaster;
}; // class Observer
#endif // OBSERVER_H_
Observer.cpp
#include "Observer.h" // include header file
Observer::Observer(SubjectInterface* Master)
{
Master->Attach(this);
}
Observer::~Observer()
{
}
When I compile this using the gcc 4.3.4, I get the following error message:
SubjectInterface.h:10: error: ‘Observer’ has not been declared
I don't understand this, because the Observer is included just a few lines above. When I change the pointer type from Observer* to int*, it compiles OK. I assume that there is a problem with the template subject and the non-template interface to it, but that is not what gcc is telling me and that doesn't seem to be the problem when using int*.
I searched for template/observer, but what I found (e.g. Implementing a Subject/Observer pattern with templates) is not quite what I need.
Can anyone tell me, what I did wrong or how I can call the templated attach-method from a non-template observer?
You have a circular include chain, SubjectInterface.h includes Observer.h which in turns includes SubjectInterface.h.
This means that the include guards will prevent Observer from being visible. To fix it instead forward declare Observer.
// SubjectInterface.h
#ifndef SUBJECTINTERFACE_H_
#define SUBJECTINTERFACE_H_
#include <list>
class Observer; //Forward declaration
// Template-independant interface for registering observers
class SubjectInterface
{
public:
virtual void Attach(Observer*) = 0;
}; // class SubjectInterface
#endif // SUBJECTINTERFACE_H_
You have a circular dependency; Observer.h includes SubjectInterface.h, and vice versa. You will need to break this with a forward declaration.