I have a C++ project which is divided into subproject. One of the projects has a factory implemented with a template member function that injects dependencies, similar to this:
class FooManager {
public:
// stuff
template<class TBar>
TBar makeInstance() {
return TBar(depA, depB);
}
private:
DependencyA depA;
DependencyB depB;
};
Now, the problem is that this forces DependencyA and DependencyB to be a part of the interface of FooManager.
Is there any way to have a template member function to work as a factory method but in a way that it hides the injected types from the interface?
edit: hiding depA and depB in a pimpl is an option on the table, so is explicit template specialization for all TBar types.
Related
I am writing a shared library (call it MyLib) which depends on another library (call it ParentLib). The ParentLib has a few virtual functions which I am implementing in MyLib along with several other independent implementations.
// MyLib.h
#include <parentlib_library.h>
class Foo : public ClassinParent
{
public:
void DefinitionofParentLibFunction();
private:
// ...
};
I was able to compile and generate the MyLib with no issues but when the MyLib is used by the application, I need to include the ParentLib_library.h to compile the code.
One of my requirements is that the ParentLib should be completely hidden from the application. I am not sure of the next step to achieve this.
Any ideas?
If your declaration used in callback or implementation of interface from 3dparty lib - then no way. In all another cases I usually apply following 3 approaches.
1) Use aggregation. Declare ClassInParent as forward and use as member of Foo:
class ClassInParent;//forward declare
class Foo
{
ClassInParent* _inst; //use either pointer of reference to external
public:
void method_of_ClassInParent() //make facade for parent methods if needed
}
2) Separate your class into interface (that is not depended on ClassInParent) and implementation (that is not expose via #include)
Your Foo.h:
class Foo
{
public:
virtual void do_smth() = 0;
};
Your Foo.cpp:
#include <parentlib_library.h>
class FooImpl : public Foo, public ClassInParent
{
void do_smth()
{//implementation
3) Use templates. Instead of explicit inherience use template:
template <class T>
class Foo : public T
{
Later in your code Foo<ClassInParent>
I have the following method declared in the public area of a class like that:
In the header file:
class EntityManager
{
public:
...
template <typename ComponentType>
bool addComponentToEntity(const Entity in_Entity, const shared_ptr<ComponentType> in_ComponentInstance);
...
}
In the source file:
template <typename ComponentType>
bool EntityManager::addComponentToEntity(const Entity in_Entity, const shared_ptr<ComponentType> in_ComponentInstance)
{
...
}
Then I try to use it like this:
Entity l_Entity = 1;
shared_ptr<TestComponent> l_TestComponent(new TestComponent());
EntityManager* l_EntityManager = new EntityManager();
l_EntityManager->addComponentToEntity<TestComponent>(l_Entity, l_TestComponent);
This results in the compiler complaining:
undefined reference to `bool EntityManager::addComponentToEntity<TestComponent>(unsigned long, boost::shared_ptr<TestComponent>)'|
I am aware that this is probably because I am not very experienced in C++ programming, but I can't see a reason why the function is undefined. I ommitted some other code that calls other functions of the EntityManager class and that works perfectly well.
I also tried rewriting the function with regular pointers, references and even passes by value with the same result.
Template methods/functions must be defined in the header itself (unless the method's class itself is defined in a source file). This is also the case for all methods of a template class (even if the methods themselves aren't template methods).
Most people don't even bother defining them below the class definition, they just define them inline inside the class:
class EntityManager
{
public:
...
template <typename ComponentType>
bool addComponentToEntity(const Entity in_Entity, const shared_ptr<ComponentType> in_ComponentInstance)
{
...
}
...
}
I am trying to create a templated factory class that exports a create method:
template <typename T>
class ClassFactory
{
_declspec(dllexport) static void* Create()
{
return new T;
}
};
class Foobar : ClassFactory<Foobar>
{
std::string foo;
};
This code compiles just fine, but I don't see anything in the exports table when I look at the output of dumpbin /exports
The following code exports Create() correctly:
class ClassFactoryBase
{
_declspec(dllexport) virtual void* Create() = 0;
};
template <typename T>
class ClassFactory : ClassFactoryBase
{
void* Create()
{
return new T;
}
};
class Foobar : ClassFactory<Foobar>
{
std::string foo;
};
However, I need Create() to be static. Why does sample 2 work, while sample 1 does not? Is there a way to export a static template method?
The compiler sees that the Create() function is never called so it does not generate any code for it. To make it work you need to explicitly instantiate your template like this:
template class ClassFactory<Foobar>;
Just add this line to your source. Now the compiler will generate the code for this function and export it. For more information see this MSDN article - Explicit Instantiation (C++)
To answer your other question why the example 2 works and example 1 does not, let's take a closer look at the derived class Foobar. There is a virtual function in this class so the compiler has to generate a vtable. To fill in the vtable the compiler needs to know the address of Create() and this is when it is implicitly instantiated from the base class template. The code for this function is generated and exported to the DLL, as requested. That is why the example 2 works.
There is no way to export a template method from the DLL, because non-instanced template method is not even compiled. Your examples doesn't do much with the DLL itself, the header file is the one, who makes everything work.
I want to use the pimpl idiom to avoid having users of my library need our external dependencies (like boost, etc) however when my class is templated that seems to be impossible because the methods must be in the header. Is there something I can do instead?
If the class is templated, your users essentially need to compile it (and this is literally true in the most widely-used C++ implementations) and so they need your external dependencies.
The simplest solution is to put the bulk of your class's implementation in a non-template base class (or encapsulated member object of some class). Solve the module-hiding problem there.
And then write the template derived (or enclosing) class to add type safety to it.
For example, suppose you have a template that provides the amazing ability to allocate on first access (omitting the necessary copy constructor, assignment, destructor):
template <class T>
class MyContainer
{
T *instance_;
public:
MyContainer() : instance_(0) {}
T &access()
{
if (instance_ == 0)
instance_ = new T();
return *instance_;
}
};
If you wanted the "logic" to be separated into a non-template base class, you'd have to parameterise the behaviour in the non-template way, which is to say, use virtual functions:
class MyBase
{
void *instance_;
virtual void *allocate() = 0;
public:
MyBase() : instance_(0) {}
void *access()
{
if (instance_ == 0)
instance_ = allocate();
return instance_;
}
};
Then you can add the type-awareness in the outer layer:
template <class T>
class MyContainer : MyBase
{
virtual void *allocate()
{ return new T(); }
public:
T &access()
{ return *(reinterpret_cast<T *>(MyBase::access())); }
};
i.e. You use virtual functions to allow the template to "fill in" the type-dependent operations. Obviously this pattern would only really make sense if you have some business logic that is worth the effort of hiding.
You can explicitly instantiate templates in the source file, but that is possible only if you know what the template type is going to be. Otherwise, do not use pimpl idiom for templates.
Something like this :
header.hpp :
#ifndef HEADER_HPP
#define HEADER_HPP
template< typename T >
class A
{
// constructor+methods + pimpl
};
#endif
source.cpp :
#include "header.hpp"
// implementation
// explicitly instantiate for types that will be used
template class A< int >;
template class A< float >;
// etc...
There are two general solutions:
while the interface depends on some type T, it defers to a more weakly typed implementation (e.g. one using void* pointers directly or trough type erasure), or
you support only a specific and quite limited number of types.
The second solution is relevant for e.g. char/wchar_t-dependent stuff.
The first solution was quite common in the early days of C++ templates, because at that time compilers were not good at recognizing commonalities in the generated machine code, and would introduce so called “code bloat”. Today, much to the surprise of any novice who tries it out, a templated solution can often have smaller machine code footprint than a solution relying on runtime polymorphism. Of course, YMMV.
Cheers & hth.,
After asking this question and reading up a lot on templates, I am wondering whether the following setup for a class template makes sense.
I have a class template called ResourceManager that will only be loading a few specific resources like ResourceManager<sf::Image>, ResourceManager<sf::Music>, etc. Obviously I define the class template in ResourceManager.h . However, since there are only a few explicit instantiations, would it be appropriate to do something like...
// ResourceManager.cpp
template class ResourceManager<sf::Image>;
template class ResourceManager<sf::Music>;
...
// Define methods in ResourceManager, including explicit specializations
In short, I'm trying to find the cleanest way to handle declaring and defining a template class and its methods, some of which may be explicit specializations. This is a special case, in which I know that there will only be a few explicit instantiations used.
Yes.
This is perfectly legittamate.
You may want to hide the fact that it is templatised behind a typedef (like std::basic_string does) then put a comment in the header not to use the template explicitly.
ResourceManager.h
template<typename T>
class ResourceManager
{
T& getType();
};
// Do not use ResourceManager<T> directly.
// Use one of the following types explicitly
typedef ResourceManager<sf::Image> ImageResourceManager;
typedef ResourceManager<sf::Music> MusicResourceManager;
ResourceManager.cpp
#include "ResourceManager.h"
// Code for resource Manager
template<typename T>
T& ResourceManager::getType()
{
T newValue;
return newValue;
}
// Make sure only explicit instanciations are valid.
template class ResourceManager<sf::Image>;
template class ResourceManager<sf::Music>;
If you require different implementations of the functions, depending on the type, I'd recommend using inheritance instead of templates.
class ResourceManager {
// Virtual and non-virtual functions.
}
class ImageManager : public ResourceManager {
// Implement virtual functions.
}
class MusicManager : public ResourceManager {
// Implement virtual functions.
}