I'm writing some code were I'm gonna end up (un)loading many different files. For this reason I'm working on a content manager to manage those files. When a file is loaded through the content manager, it is turned into an instance of an appropiate class.
1 2 3 4 5 6 7 8 9 10
//Class ContentManager
class ContentManager {
//private fields and methods
public:
Content* Load(string path);
};
class Content {
void Load(string path) = 0;
};
The Content class is a base class for all the different files that can be loaded. When you call the Load method of the ContentManager, it returns a pointer to the loaded resource, which I can the use.
What I would like to be able to do is to write something like this:
Basically the manager will create an instance of the template specified class and then call the Load method on that. So is it possible to make a template function but restrict, so that you can only use classes with Content as base class? Or is there an other/better way to achieve this effect?
There is no direct way to say something like "template parameter must be a subclass of FooBar" but there are some ways to emulate the desired behaviour. (A direct way would have been "concepts" which just have been kicked out of the next C++ language version).
For example, you can assign a pointer of your template argument to the base class pointer. This works only for subclasses and hence you get a compile time error if it isn't like that. The compiler should eliminate the useless initialization anyway, so no runtime hit should occur here.
1 2 3 4 5 6 7
struct ContentManager {
template<class C>
void Load() {
Content* dummy = (C*)0; // if you get an error, you didn't pass a subclass of Content!
...
}
};
A more elaborated approach (with better error messages) is to use Boost::concepts but I never used them personally, so no example here. But it shouldn't be too hard to get some example out of their docu..
Ciao, Imi.
PS: class ContentB : Content {};
I hope you forgot a "public" here? private inheritance is not so easy to detect nor should you try to do it anyway.
PPS:
1 2
//Class ContentManager
class ContentManager {
Zing! Hereby you got the MUC-award ("Most Useless Comment"). (sorry, couldn't resist :-D)
#include <boost/type_traits_is_base_of.hpp>
#include <boost/utility/enable_if.hpp>
struct ContentManager {
template< class C >
void Load( boost::enable_if< boost::is_base_of< Content, C >, void* >::type = 0 )
{ /* do work */ }
};
This will restrict the Load function to accepting only Cs that are derived from Content.
[Note: above is uncompiled.]
Though I 'd go with a flavor of imi's original suggestion instead, though as is the solution given will generate
compile warnings re: unused variables.
Since we both (jsmith and me) forgot the const char* parameter with the filename, you could use this instead of the void* dummy type in the boost::enable_if example. ;-)