Templates and dependency injection - c++

I have a class template ResourceManager and it is intended to be used something like this:
ResourceManager<Image>* rm =
ResourceManager<Image>::Instance();
Image* img = rm->acquire("picture.jpg");
rm->release(img);
I'd like to use dependency injection (pass the ResourceManager as a parameter to functions that are supposed to use it instead of having it used globally), however given that it's a template I don't know how to do this. Do you have any suggestions?
My game is only at the beginning of the development and I already have four resource types (Image, Font, Animation and Sound) so making a single ResourceManager (i.e. not a template) with an acquire function for each type of resource is not an option.
Edit: Some clarifications.
What I'm looking for is not how to do dependency injection for one type of ResourceManager, but for all of them at once.
My GameState objects need to load resources when they are initialized/opened; they do so through the ResourceManagers. However, GameStates may need to load any number of types of resources: animations, fonts, images, sounds, etc — that's a lot of function parameters for each kind of ResourceManager! What do you suggest I do?

Well, if the function needs a particular kind of resource (most will, probably), just define the specific template instance as parameter:
function(ResourceManager<Image> *rm, ...);
If the function needs any kind of resource than it can either
Be a template itself, like:
template <typename T>
function(ResourceManager<T> *rm, ...);
It will probably need to refer to the resource obtained from resource manager, so it will need the template argument in more places anyway.
Use a polymorphic base class. That would mean you'd have to define something like
class ResourceManagerBase { /* methods you need to call via the base class */ };
template <typename T>
class ResourceManager : ResourceManagerBase { ... };
function(ResourceManagerBase *rm, ...)
The function can call any methods defined in the base class. If the methods depend on resource-type internally, they will be declared abstract virtual (virtual returnType method(...) = 0) in the base and defined in the template class itself. You can also use dynamic_cast to check which particular instantiation of ResourceManager you've got.
Note, that if the function needs to refer to the resource, you will similarly need a ResourceBase abstract base class of all resources, so you can refer to any kind of resource.
The choice is matter of trade-off between faster but very large code with template function (the function will be compiled for each specialization separately) or slower but smaller code with virtual methods (call to virtual method is slower, but there is no code duplication). Also the template variant will compile slower, because most compilers will generate the code for each object file that uses it and than merge identical copies at link time.

First. Remember when you use templates, you must resolve everything at compile time.
Then ResourceManager in your code seems a singleton. So there's no difference, rougly speaking, with a global variable.
And I think that is useless pass rm as parameters of your functions when you can call the singleton directly.
And this resolves, I hope, your question.

An example using constructor injection:
template<typename T>
struct ResourceManager
{
virtual T* acquire(std::string const& resourceName)
{ return ...; }
... etc ...
};
class ImageUser
{
ResourceManager<Image>* rm_;
public:
explicit ImageUser(ResourceManager<Image>* rm)
: rm_(rm)
{}
ImageUser()
: rm_(ResourceManager<Image>::Instance())
{}
void UseImage()
{
Image* img = rm_->acquire("picture.jpg");
rm_->release(img);
}
};
struct ImageResourceManagerFake : ResourceManager<Image>
{
virtual Image* acquire(std::string const& resourceName) // override
{ return <whatever-you-want>; }
... etc ...
};
void test_imageuser()
{
ImageResourceManagerFake* rm = new ImageResourceManagerFake;
ImageUser iu(rm);
... test away ...
}
Note that I've left out all resource management; use smart pointers etc wherever applicable.

Even after your edit I find it a little hard to understand what you're after without seeing the whole picture, but I'll make a second attempt at a basic example:
template<typename T>
struct ResourceManager
{
virtual T* acquire(std::string const& resourceName)
{ return ...; }
// ... etc ...
};
class ImageUser
{
ResourceManager<Image>* rm_;
public:
explicit ImageUser(ResourceManager<Image>* rm)
: rm_(rm)
{}
void UseImage()
{
Image* img = rm_->acquire("picture.jpg");
rm_->release(img);
}
};
template<typename T>
struct ResourceManagerFake : ResourceManager<T>
{
T* acquireRetVal;
virtual T* acquire(std::string const& resourceName)
{ return acquireRetVal; }
// ... etc ...
};
void test_imageuser()
{
ResourceManagerFake<Image>* rm = new ResourceManagerFake<Image>;
rm->acquireRetVal = new Image;
ImageUser iu(rm);
iu.UseImage();
}
Note to commenters: I'm well aware of the resource leaks, but that's not the point here.

Related

Simplify an extensible "Perform Operation X on Data Y" framework

tl;dr
My goal is to conditionally provide implementations for abstract virtual methods in an intermediate workhorse template class (depending on template parameters), but to leave them abstract otherwise so that classes derived from the template are reminded by the compiler to implement them if necessary.
I am also grateful for pointers towards better solutions in general.
Long version
I am working on an extensible framework to perform "operations" on "data". One main goal is to allow XML configs to determine program flow, and allow users to extend both allowed data types and operations at a later date, without having to modify framework code.
If either one (operations or data types) is kept fixed architecturally, there are good patterns to deal with the problem. If allowed operations are known ahead of time, use abstract virtual functions in your data types (new data have to implement all required functionality to be usable). If data types are known ahead of time, use the Visitor pattern (where the operation has to define virtual calls for all data types).
Now if both are meant to be extensible, I could not find a well-established solution.
My solution is to declare them independently from one another and then register "operation X for data type Y" via an operation factory. That way, users can add new data types, or implement additional or alternative operations and they can be produced and configured using the same XML framework.
If you create a matrix of (all data types) x (all operations), you end up with a lot of classes. Hence, they should be as minimal as possible, and eliminate trivial boilerplate code as far as possible, and this is where I could use some inspiration and help.
There are many operations that will often be trivial, but might not be in specific cases, such as Clone() and some more (omitted here for "brevity"). My goal is to conditionally provide implementations for abstract virtual methods if appropriate, but to leave them abstract otherwise.
Some solutions I considered
As in example below: provide default implementation for trivial operations. Consequence: Nontrivial operations need to remember to override with their own methods. Can lead to run-time problems if some future developer forgets to do that.
Do NOT provide defaults. Consequence: Nontrivial functions need to be basically copy & pasted for every final derived class. Lots of useless copy&paste code.
Provide an additional template class derived from cOperation base class that implements the boilerplate functions and nothing else (template parameters similar to specific operation workhorse templates). Derived final classes inherit from their concrete operation base class and that template. Consequence: both concreteOperationBase and boilerplateTemplate need to inherit virtually from cOperation. Potentially some run-time overhead, from what I found on SO. Future developers need to let their operations inherit virtually from cOperation.
std::enable_if magic. Didn't get the combination of virtual functions and templates to work.
Here is a (fairly) minimal compilable example of the situation:
//Base class for all operations on all data types. Will be inherited from. A lot. Base class does not define any concrete operation interface, nor does it necessarily know any concrete data types it might be performed on.
class cOperation
{
public:
virtual ~cOperation() {}
virtual std::unique_ptr<cOperation> Clone() const = 0;
virtual bool Serialize() const = 0;
//... more virtual calls that can be either trivial or quite involved ...
protected:
cOperation(const std::string& strOperationID, const std::string& strOperatesOnType)
: m_strOperationID()
, m_strOperatesOnType(strOperatesOnType)
{
//empty
}
private:
std::string m_strOperationID;
std::string m_strOperatesOnType;
};
//Base class for all data types. Will be inherited from. A lot. Does not know any operations that might be performed on it.
struct cDataTypeBase
{
virtual ~cDataTypeBase() {}
};
Now, I'll define an example data type.
//Some concrete data type. Still does not know any operations that might be performed on it.
struct cDataTypeA : public cDataTypeBase
{
static const std::string& GetDataName()
{
static const std::string strMyName = "cDataTypeA";
return strMyName;
}
};
And here is an example operation. It defines a concrete operation interface, but does not know the data types it might be performed on.
//Some concrete operation. Does not know all data types it might be expected to work on.
class cConcreteOperationX : public cOperation
{
public:
virtual bool doSomeConcreteOperationX(const cDataTypeBase& dataBase) = 0;
protected:
cConcreteOperationX(const std::string& strOperatesOnType)
: cOperation("concreteOperationX", strOperatesOnType)
{
//empty
}
};
The following template is meant to be the boilerplate workhorse. It implements as much trivial and repetitive code as possible and is provided alongside the concrete operation base class - concrete data types are still unknown, but are meant to be provided as template parameters.
//ConcreteOperationTemplate: absorb as much common/trivial code as possible, so concrete derived classes can have minimal code for easy addition of more supported data types
template <typename ConcreteDataType, typename DerivedOperationType, bool bHasTrivialCloneAndSerialize = false>
class cConcreteOperationXTemplate : public cConcreteOperationX
{
public:
//Can perform datatype cast here:
virtual bool doSomeConcreteOperationX(const cDataTypeBase& dataBase) override
{
const ConcreteDataType* pCastData = dynamic_cast<const ConcreteDataType*>(&dataBase);
if (pCastData == nullptr)
{
return false;
}
return doSomeConcreteOperationXOnCastData(*pCastData);
}
protected:
cConcreteOperationXTemplate()
: cConcreteOperationX(ConcreteDataType::GetDataName()) //requires ConcreteDataType to have a static method returning something appropriate
{
//empty
}
private:
//Clone can be implemented here via CRTP
virtual std::unique_ptr<cOperation> Clone() const override
{
return std::unique_ptr<cOperation>(new DerivedOperationType(*static_cast<const DerivedOperationType*>(this)));
}
//TODO: Some Magic here to enable trivial serializations, but leave non-trivials abstract
//Problem with current code is that virtual bool Serialize() override will also be overwritten for bHasTrivialCloneAndSerialize == false
virtual bool Serialize() const override
{
return true;
}
virtual bool doSomeConcreteOperationXOnCastData(const ConcreteDataType& castData) = 0;
};
Here are two implementations of the example operation on the example data type. One of them will be registered as the default operation, to be used if the user does not declare anything else in the config, and the other is a potentially much more involved non-default operation that might take many additional parameters into account (these would then have to be serialized in order to be correctly re-instantiated on the next program run). These operations need to know both the operation and the data type they relate to, but could potentially be implemented at a much later time, or in a different software component where the specific combination of operation and data type are required.
//Implementation of operation X on type A. Needs to know both of these, but can be implemented if and when required.
class cConcreteOperationXOnTypeADefault : public cConcreteOperationXTemplate<cDataTypeA, cConcreteOperationXOnTypeADefault, true>
{
virtual bool doSomeConcreteOperationXOnCastData(const cDataTypeA& castData) override
{
//...do stuff...
return true;
}
};
//Different implementation of operation X on type A.
class cConcreteOperationXOnTypeASpecialSauce : public cConcreteOperationXTemplate<cDataTypeA, cConcreteOperationXOnTypeASpecialSauce/*, false*/>
{
virtual bool doSomeConcreteOperationXOnCastData(const cDataTypeA& castData) override
{
//...do stuff...
return true;
}
//Problem: Compiler does not remind me that cConcreteOperationXOnTypeASpecialSauce might need to implement this method
//virtual bool Serialize() override {}
};
int main(int argc, char* argv[])
{
std::map<std::string, std::map<std::string, std::unique_ptr<cOperation>>> mapOpIDAndDataTypeToOperation;
//...fill map, e.g. via XML config / factory method...
const cOperation& requestedOperation = *mapOpIDAndDataTypeToOperation.at("concreteOperationX").at("cDataTypeA");
//...do stuff...
return 0;
}
if you data types are not virtual (for each operation call you know both operation type and data type at compile time) you may consider following approach:
#include<iostream>
#include<string>
template<class T>
void empty(T t){
std::cout<<"warning about missing implementation"<<std::endl;
}
template<class T>
void simple_plus(T){
std::cout<<"simple plus"<<std::endl;
}
void plus_string(std::string){
std::cout<<"plus string"<<std::endl;
}
template<class Data, void Implementation(Data)>
class Operation{
public:
static void exec(Data d){
Implementation(d);
}
};
#define macro_def(OperationName) template<class T> class OperationName : public Operation<T, empty<T>>{};
#define macro_template_inst( TypeName, OperationName, ImplementationName ) template<> class OperationName<TypeName> : public Operation<TypeName, ImplementationName<TypeName>>{};
#define macro_inst( TypeName, OperationName, ImplementationName ) template<> class OperationName<TypeName> : public Operation<TypeName, ImplementationName>{};
// this part may be generated on base of .xml file and put into .h file, and then just #include generated.h
macro_def(Plus)
macro_template_inst(int, Plus, simple_plus)
macro_template_inst(double, Plus, simple_plus)
macro_inst(std::string, Plus, plus_string)
int main() {
Plus<int>::exec(2);
Plus<double>::exec(2.5);
Plus<float>::exec(2.5);
Plus<std::string>::exec("abc");
return 0;
}
Minus of this approach is that you'd have to compile project in 2 steps: 1) transform .xml to .h 2) compile project using generated .h file. On plus side compiler/ide (I use qtcreator with mingw) gives warning about unused parameter t in function
void empty(T t)
and stack trace where from it was called.

Call function of template class created at runtime

I have a tricky question about C++(11) template classes and their instantiation with types determined at runtime:
Following scenario:
The user defines the type of a template class using a config file (ROS parameters). This determines only the type of the template class, not the further logic:
Class definition:
template<typename T>
class MyClass {
//[...]
}
Exemplary code:
/* [Read parameter and write result to bool use_int] */
std::unique_ptr<MyClass> myclassptr {nullptr};
if(use_int) {
myclassptr.reset(MyClass<int>);
} else {
myclassptr.reset(MyClass<double>);
}
myclassptr->foobar();
/* [more code making use of myclassptr] */
So this code is (of course) not compiling, because the unique_ptr template must be specified also with the template type. However, then the problem arises that the template type must be the same for all objects assigned using reset.
One ugly solution would be to copy the code myclassptr->foobar(); and the following into each branch of if/else, which I really don't like.
I would like to see a solution similar to this:
/* [Read parameter and write result to bool use_int] */
MyClass<use_int ? int : double> myclass;
myclass.foobar();
What I have read so far is that something like this is also not possible.
Does anybody have a nice solution for this?
The simplest way to do this is:
class IClass{
virtual ~IClass {}
virtual void foobar()=0;
};
template<typename T>
class MyClass:public IClass {
public:
void foobar() override {
// code here
}
};
std::unique_ptr<IClass> myclassptr {};
if(use_int) {
myclassptr.reset(new MyClass<int>());
} else {
myclassptr.reset(new MyClass<double>());
}
myclassptr->foobar();
boost::variant would be another solution, but is usually used for unrelated types. Type erasure could be done, but again that is usually done when you have unrelated types you want to impose a uniform interface on.
In other languages generics look sort of like templates, but are actually an abstract interface with auto-generated typecasting and some typechecking added. C++ templates are function or class compile time factories. Two outputs of such factories are unrelated at runtime by default, and you can add such relations if you want.
Depending on what you want, you can make MyClass a variant type that holds either an int or a double, or you could use type erasure to hide the implementation behind an interface. The Boost.Variant library can help to implement the former.

Vector of pointers to instances of a templated class

I am implementing a task runtime system that maintains buffers for user-provided objects of various types. In addition, all objects are wrapped before they are stored into the buffers. Since the runtime doesn't know the types of objects that the user will provide, the Wrapper and the Buffer classes are templated:
template <typename T>
class Wrapper {
private:
T mdata;
public:
Wrapper() = default;
Wrapper(T& user_data) : mdata(user_data) {}
T& GetData() { return mdata; }
...
};
template <typename T>
class Buffer {
private:
std::deque<Wrapper<T>> items;
public:
void Write(Wrapper<T> wd) {
items.push_back(wd);
}
Wrapper<T> Read() {
Wrapper<T> tmp = items.front();
items.pop_front();
return tmp;
}
...
};
Now, the runtime system handles the tasks, each of which operates on a subset of aforementioned buffers. Thus, each buffer is operated by one or more tasks. This means that a task must keep references to the buffers since the tasks may share buffers.
This is where my problem is:
1) each task needs to keep references to a number of buffers (this number is unknown in compile time)
2) the buffers are of different types (based on the templeted Buffer class).
3) the task needs to use these references to access buffers.
There is no point to have a base class to the Buffer class and then use base class pointers since the methods Write and Read from the Buffer class are templeted and thus cannot be virtual.
So I was thinking to keep references as void pointers, where the Task class would look something like:
class Task {
private:
vector<void *> buffers;
public:
template<typename T>
void AddBuffer(Buffet<T>* bptr) {
buffers.push_back((void *) bptr);
}
template<typename T>
Buffer<T>* GetBufferPtr(int index) {
return some_way_of_cast(buffers[index]);
}
...
};
The problem with this is that I don't know how to get the valid pointer from the void pointer in order to access the Buffer. Namely, I don't know how to retain the type of the object pointed by buffers[index].
Can you help me with this, or suggest some other solution?
EDIT: The buffers are only the implementation detail of the runtime system and the user is not aware of their existence.
In my experience, when the user types are kept in user code, run-time systems handling buffers do not need to worry about the actual type of these buffer. Users can invoke operations on typed buffers.
class Task {
private:
vector<void *> buffers;
public:
void AddBuffer(char* bptr) {
buffers.push_back((void *) bptr);
}
char *GetBufferPtr(int index) {
return some_way_of_cast(buffers[index]);
}
...
};
class RTTask: public Task {
/* ... */
void do_stuff() {
Buffer<UserType1> b1; b1Id = b1.id();
Buffer<UserType2> b2; b2Id = b2.id();
AddBuffer(cast(&b1));
AddBuffer(cast(&b2));
}
void do_stuff2() {
Buffer<UserType1> *b1 = cast(GetBufferPtr(b1Id));
b1->push(new UserType1());
}
};
In these cases casts are in the user code. But perhaps you have a different problem. Also the Wrapper class may not be necessary if you can switch to pointers.
What you need is something called type erasure. It's way to hide the type(s) in a template.
The basic technique is the following:
- Have an abstract class with the behavior you want in declared in a type independent maner.
- Derive your template class from that class, implement its virtual methods.
Good news, you probably don't need to write your own, there boost::any already. Since all you need is get a pointer and get the object back, that should be enough.
Now, working with void* is a bad idea. As perreal mentioned, the code dealing with the buffers should not care about the type though. The good thing to do is to work with char*. That is the type that is commonly used for buffers (e.g. socket apis). It is safer than too: there is a special rule in the standard that allows safer conversion to char* (see aliasing rules).
This isn't exactly an answer to your question, but I just wanted to point out that the way you wrote
Wrapper<T> Read() {
makes it a mutator member function which returns by value, and as such, is not good practice as it forces the user write exception unsafe code.
For the same reason the STL stack::pop() member function returns void, not the object that was popped off the stack.

Should I prefer mixins or function templates to add behavior to a set of unrelated types?

Mixins and function templates are two different ways of providing a behavior to a wide set of types, as long as these types meet some requirements.
For example, let's assume that I want to write some code that allows me to save an object to a file, as long as this object provides a toString member function (this is a rather silly example, but bear with me). A first solution is to write a function template like the following:
template <typename T>
void toFile(T const & obj, std::string const & filename)
{
std::ofstream file(filename);
file << obj.toString() << '\n';
}
...
SomeClass o1;
toFile(o1, "foo.txt");
SomeOtherType o2;
toFile(o2, "bar.txt");
Another solution is to use a mixin, using CRTP:
template <typename Derived>
struct ToFile
{
void toFile(std::string const & filename) const
{
Derived * that = static_cast<Derived const *>(this);
std::ofstream file(filename);
file << that->toString() << '\n';
}
};
struct SomeClass : public ToFile<SomeClass>
{
void toString() const {...}
};
...
SomeClass o1;
o.toFile("foo.txt");
SomeOtherType o2;
o2.toFile("bar.txt");
What are the pros and cons of these two approaches? Is there a favored one, and if so, why?
The first approach is much more flexible, as it can be made to work with any type that provides any way to be converted to a std::string (this can be achieved using traits-classes) without the need to modify that type. Your second approach would always require modification of a type in order to add functionality.
Pro function templates: the coupling is looser. You don't need to derive from anything to get the functionality in a new class; in your example, you only implement the toString method and that's it. You can even use a limited form of duck typing, since the type of toString isn't specified.
Pro mixins: nothing, strictly; your requirement is for something that works with unrelated classes and mixins cause them to be become related.
Edit: Alright, due to the way the C++ type system works, the mixin solution will strictly produce unrelated classes. I'd go with the template function solution, though.
I would like to propose an alternative, often forgotten because it is a mix of duck-typing and interfaces, and very few languages propose this feat (note: very close to Go's take to interfaces actually).
// 1. Ask for a free function to exist:
void toString(std::string& buffer, SomeClass const& sc);
// 2. Create an interface that exposes this function
class ToString {
public:
virtual ~ToString() {}
virtual void toString(std::string& buffer) const = 0;
}; // class ToString
// 3. Create an adapter class (bit of magic)
template <typename T>
class ToStringT final: public ToString {
public:
ToStringT(T const& t): t(t) {}
virtual void toString(std::string& buffer) const override {
toString(buffer, t);
}
private:
T t; // note: for reference you need a reference wrapper
// I won't delve into this right now, suffice to say
// it's feasible and only require one template overload
// of toString.
}; // class ToStringT
// 4. Create an adapter maker
template <typename T>
ToStringT<T> toString(T const& t) { return std::move(ToStringT<T>(t)); }
And now ? Enjoy!
void print(ToString const& ts); // aka: the most important const
int main() {
SomeClass sc;
print(toString(sc));
};
The two stages is a bit heavyweight, however it gives an astonishing degree of functionality:
No hard-wiring data / interface (thanks to duck-typing)
Low-coupling (thanks to abstract classes)
And also easy integration:
You can write an "adapter" for an already existing interface, and migrate from an OO code base to a more agile one
You can write an "interface" for an already existing set of overloads, and migrate from a Generic code base to a more clustered one
Apart from the amount of boiler-plate, it's really amazing how you seamlessly pick advantages from both worlds.
A few thoughts I had while writing this question:
Arguments in favor of template functions:
A function can be overloaded, so third-party and built-in types can be handled.
Arguments in favor of mixins:
Homogeneous syntax: the added behavior is invoked like any other member functions. However, it is well known that the interface of a C++ class includes not only its public member functions but also the free functions that operates on instances of this type, so this is just an aesthetic improvement.
By adding a non-template base class to the mixins, we obtain an interface (in the Java/C# sense) that can be use to handle all objects providing the behavior. For example, if we make ToFile<T> inherits from FileWritable (declaring a pure virtual toFile member function), we can have a collection of FileWritable without having to resort to complicated heterogeneous data structures.
Regarding usage, I'd say that function templates are more idiomatic in C++.

Alternative to Factory Pattern when creating templated objects - C++

I want to implement a Mesh class for a CG project, but have run into some problems.
What I want to do is a Mesh class that hides implementation details (like loading to a specific API: OpenGL, DirectX, CUDA, ...) from the user. Additionally, since the Mesh class will be used in research projects, this Mesh class has to be very flexible.
class Channel {
virtual loadToAPI() = 0;
}
template <class T>
class TypedChannel : public Channel {
std::vector<T> data;
};
template <class T>
class OpenGLChannel : public TypedChannel<T> {
loadToAPI(); // implementation
};
class Mesh {
template<class T>
virtual TypedChannel<T>* createChannel() = 0; // error: no virtual template functions
std::vector<Channel*> channels;
};
class OpenGLMesh {
template<class T>
TypedChannel<T>* createChannel()
{
TypedChannel<T>* newChannel = new OpenGLChannel<T>;
channels.push_back(newChannel);
return newChannel;
};
};
For flexibility, each Mesh is really a collection of channels, like one position channel, a normal channel, etc. that describe some aspects of the mesh. A channel is a wrapper around a std::vector with some added functionality.
To hide implementation details, there is a derived class for each API (OpenGLMesh, DirectXMesh, CUDAMesh, ...) that handles API-specific code. The same goes for the Channels (OpenGLChannel, etc. that handle loading of the Channel data to the API). The Mesh acts as a factory for the Channel objects.
But here is the problem: Since the Channels are template classes, createChannel must be a template method, and template methods cannot be virtual. What I would need is something like a Factory Pattern for creating templated objects. Does anyone have advice on how something similar could be accomplished?
Thanks
It's an interesting problem, but let's discuss the compiler error first.
As the compiler said, a function cannot be both virtual and template. To understand why, just think about the implementation: most of the times, objects with virtual functions have a virtual table, which stores a pointer to each function.
For templates however, there are as many functions as combinations of type: so what should be the virtual table like ? It's impossible to tell at compilation time, and the memory layout of your class includes the virtual table and has to be decided at compilation time.
Now on to your problem.
The simplest solution would be to just write one virtual method per type, of course it can soon become tedious, so let's pretend you haven't heard that.
If Mesh is not supposed to know about the various types, then surely you don't need the function to be virtual, because who would know, given an instance of Mesh, with which type invoking the function ?
Mesh* mesh = ...;
mesh.createChannel<int>(); // has it been defined for that `Mesh` ??
On the other hand, I will suppose that OpenGLMesh does know exactly which kind of TypedChannel it will need. If so, we could use a very simple trick.
struct ChannelFactory
{
virtual ~ChannelFactory() {}
virtual Channel* createChannel() = 0;
};
template <class T>
struct TypedChannelFactory: ChannelFactory
{
};
And then:
class Mesh
{
public:
template <class T>
Channel* addChannel()
{
factories_type::const_iterator it = mFactories.find(typeid(T).name());
assert(it != mFactories.end() && "Ooops!!!" && typeid(T).name());
Channel* channel = it->second->createChannel();
mChannels.push_back(channel);
return channel;
} // addChannel
protected:
template <class T>
void registerChannelFactory(TypedChannelFactory<T>* factory)
{
mFactories.insert(std::make_pair(typeid(T).name(), factory));
} // registerChannelFactory
private:
typedef std::map < const char*, ChannelFactory* const > factories_type;
factories_type mFactories;
std::vector<Channel*> mChannels;
}; // class Mesh
It demonstrates a quite powerful idiom known as type erasure. You probably used it even before you knew the name :)
Now, you can define OpenGLMesh as:
template <class T>
struct OpenGLChannelFactory: TypedChannelFactory<T>
{
virtual Channel* createChannel() { return new OpenGLChannel<T>(); }
};
OpenGLMesh::OpenGLMesh()
{
this->registerChannelFactory(new OpenGLChannelFactory<int>());
this->registerChannelFactory(new OpenGLChannelFactory<float>());
}
And you'll use it like:
OpenGLMesh openGLMesh;
Mesh& mesh = openGLMesh;
mesh.addChannel<int>(); // fine
mesh.addChannel<float>(); // fine
mesh.addChannel<char>(); // ERROR: fire the assert... (or throw, or do nothing...)
Hope I understood what you needed :p
If you could extract factory from Mesh (introducing some ChannelFactory), then you can use templatized factory:
template <class T>
class ChannelFactory
{
public:
virtual TypedChannel<T>* createChannel() = 0;
};
Than you could derive your OpenGLMesh from ChannelFactory, , , whatever.
The only limitation of this approach is that you should know beforehand which template parameters you want use in OpenGLMesh.
Otherwise you could be interested how Boost.Any works (boost::any holds values of arbitrary type).
I'd say your whole design is broken.
virtual TypedChannel<T>* createChannel() = 0; // error: no virtual template functions
std::vector<Channel*> channels;
These two lines just don't make any sense together. Don't try to fix compiler error, think over your concepts.
To start, what exactly is your reasoning for making CreateChannel a virtual member?
To put it another way, C++ is a language known for allowing all kinds of tangled unintelligible designs. And you managed to design something that even C++ thinks is too twisted.
By channel do you mean 'spacial index'?
If you want to hide implementation details, why do you have them right in your mesh?
You want the mesh to be the same basic format, maybe templating on float, double or morton numbers in different cases. It's not the mesh that should change, just the way it gets loaded.