Templates and specific base class

Hi,

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:
1
2
3
4
5
6
7
8
class ContentA : Content {};
class ContentB : Content {};

//...

ContentManager manager;
ContentA *a = manager.Load<ContentA>("filea.a");
ContentB *b = manager.Load<ContentB>("fileb.b");


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)
Thanks,
I'll try it out and take a look at boost::concepts as well.

And yes, I forgot "public". I was just writing off the top of my head and then sometimes I forget a keyword ;)

And thank you for the award. Finally I won something :D (I'll have to agree that it is a pretty useless comment ;)
Something like

1
2
3
4
5
6
7
8
#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.
Hm.. interesting approach from boost.

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. ;-)

1
2
  void Load( boost::enable_if< boost::is_base_of< Content, C >, const char* >::type filename )
  { ... }


Ciao, Imi.
Topic archived. No new replies allowed.