How to resolve a template class attribute?

Oct 7, 2010 at 2:53pm
Hello everyone,

I'm having the following problem:
Class A is a template class.
Class B has an attribute of type A.

Do I have to make B a template class, if I want to keep A general?

I'd like to resolve the template of A at runtime (e.g. in the Constructor of B), but the compiler doesn't like that. It'd like to have the template resolved at compile-time. The problem here is that I have a whole hierarchy of classes, which are linked through attributes (i.e. compositions) and if I can't get rid of the template somehow, then it goes all the way from bottom to top, since any class with a template attribute becomes a template class, of which an attribute is used in the next higher class and so on.

I've heard about the possibility of using static attributes in functions instead or the datatype "variant" from the boost-library can be used to pretend resolving the template, but which way is the most elegant one to prevent my code from becoming template-infested?

Kind regards,
Squall83
Oct 7, 2010 at 7:04pm
The problem with boost::variant is that it only supports a finite number of types, and
you probably won't be able to use it for that reason.

You have a couple of options, it seems.

Probably the best option is type erasure. Read my article:
http://www.cplusplus.com/forum/articles/18756/

Option 2 is use boost::any to hide the type, but that requires a bunch of any_casts<>
to get back to the real type, which is probably not an option for you because you
probably have way too many types to do that.

Option 3 is to do nothing and you're stuck propagating types.

Option 4 is a redesign to avoid the templates in the first place. Option 4 may or may
not be better than option 1; I don't know the details of your application.
Oct 8, 2010 at 12:35pm
Well, I only need a few basic types, so using boost wouldn't be a problem, but since templates existed before boost did, I'm interested how that problem was solved earlier.

Type erasure sounds like I'd crack a walnut with a sledgehammer if I did that. I was looking for a way to not change the complete structure of my code, i.e. keeping the templates but excluding them wherever I don't want them. It's an interesting idea though. I was having some thoughts about programming RPGs, too, but in that case I'd probably use polymorphism and downcast my items whenever necessary. My current problem is not RPG-based though.

Option 2 is my last resort if all else fails.

I don't like Option 3. I'd rather remove the template attribute from the class I want to free up and shift it into a member function where I decide how to resolve it using a switch-case statement. :-/ Could make it static for speed but it still doesn't feel to elegant. This is how I currently solved it though.

How do I redesign a template class to remove the template? Implement each template-function separately for char, short, int etc.? Giving the class a char, short, int etc. attribute for each template attribute?
Oct 8, 2010 at 2:05pm
Could you post an example of what you are trying to do? Knowing that might allow me to be more helpful.
Oct 8, 2010 at 2:27pm
Ok, I'm trying to do this:

header1.hpp contains:
1
2
3
4
5
template <class T> 
class A
{
  // ...
};



header2.hpp contains:
1
2
3
4
5
6
7
#include "header1.hpp"
class B
{
    protected:
        A<T> a;
	// ...
};


As I see it, I must make class B a template class, if I want to use the template class A and keep "a" general. But now there's class C:

header3.hpp contains:
1
2
3
4
5
6
7
#include "header2.hpp"
class C
{
    protected:
        B b;
	// ...
};


and I don't want to make this one a template-class, too. I don't want to rewrite quite a major part of my code just because somewhere down there is a template class. As soon as the constructor of B is called, I have the knowledge on how my template should look like. Therefore from a personal point of view (and not a compiler point of view) I don't need B or C to be a template class.
Oct 8, 2010 at 3:10pm
How does B use the A<T> data member? How does C use the B data member?

Type erasure, though a fairly advanced concept, may be the way to go, but it just depends on how
you are using the templated types.

The nice thing about templates is that you retain type information. Type erasure, which is what
boost::any is, allows an object to contain a templated type without itself being templated. Which
sounds like is what you want.

Polymorphism and inheritance also cause you to lose the type information. Again, depending on
how you are using these types, it may or may not be a problem to lose the type information.

Boost::variant has the limitation that it only supports a fixed number of variants (which you can
configure), so if there are a lot of Ts, then there are a lot of A<T>s and thus you might not be able
to make a variant for it. Boost::variant is absolutely fantastic for type safety, but you pay the price
of having to write a boost::static_visitor object for each different way you need to access it.

So I guess what I'm asking is can you give me a more concrete example? I understand the
syntax you are using, I just don't know how you intend on using these objects.
Oct 8, 2010 at 4:45pm
So am I understanding you correctly that there is absolutely no way to solve this by using only templates?

What I want to do is the following:
The lowest class is an image class, i.e. it contains attributes like width, height, number of color channels (RGB, Greyscale etc.), a buffer containing the actual data and so on and the template is needed for this data buffer. If the image is 8 Bit then the buffer is pointed to by an unsigned character pointer, if it's 16 bit it's unsigned short* and so on. But the image processing algorithms I'm experimenting with are working identically no matter how big the buffer is (except for writing to and reading from the buffer of course). Therefore I wanted to generalize the algorithms using a template.

Class B is system control. It gets images from the API (which is class C), pushes it to the algorithm in Class A, receives the result und returns it to the API.

Therefore the program works as follows:
- Class C has the main method and reads the image from a file. Now I know the image format and can resolve the template already.
- Class C calls Class B and gives the image to it, including the image format, so no need for a template here either.
- Class B is supposed to resolve the template of A, giving the image to it for processing.
- A returns processed image to B.
- B returns processed image to C.

I think type erasure is more suited for cases in which the classes you want to combine are very different from each other.
Oct 9, 2010 at 3:38pm
I've been thinking about this, and it seems like the image class should not be a template?

Or, perhaps the image class should contain an instance of a data buffer object which perhaps uses
type erasure to remove its type.

Not sure what that does to your design though.
Oct 11, 2010 at 6:45am
Yeah, that sounds reasonable. Up to now I resolved the template inside a function by using a switch-case statement depending on the image type. Seems to work, but it's not too elegant. If I feel like using a better solution, I'll use either type erasure or boost. I don't know yet. Thanks for the help!
Oct 11, 2010 at 1:24pm
It sounds like A should be a generalised image class, with specific derived types for each different kind of image format. I'd go for standard OO inheritance rather than a templated solution.
Oct 11, 2010 at 2:00pm
This means the generalised class has no buffer at all, while each derived class has its own buffer, right?

This way I have to copy my templated processing method into each class, don't I?
Oct 11, 2010 at 3:10pm
Possibly, it's the public methods that matter. Methods that might be different should be virtual in the base and implemented in the derived classes. Since B knows what kind of A should be used, it should create the right kind of A (using the Creator pattern), then just pass around an A pointer.
Oct 12, 2010 at 9:26am
Thanks, but for now I'll try using boost::variant.
Oct 12, 2010 at 10:11am
Hello Squall83,

Maybe you can use a pure virtual non templated base class for A. Meaning that you define all functions that you want to access as pure virtual and override them in A<T>
Oct 12, 2010 at 11:13am
So if I use the base class instead of A, B would not be templated, that's correct. And when creating the base class object, I need to call a constructor from A, right? That'd be a nice trick. I'll remember it.

Btw: Is boost::variant really able to dynamically resolve a template or is it really used to replace a template?

For now I solved my problem in Noob-style. I have 5 possibilities on how the template can look like (i.e. 5 basic data types it can take) and therefore I have 5 attributes in B, one for each template. Furthermore I have an enum that tells me which attribute to use.
Oct 12, 2010 at 11:27am
Squall83 wrote:
Is boost::variant really able to dynamically resolve a template or is it really used to replace a template?
neither. It's a replacement for union and it uses templates itself.
Topic archived. No new replies allowed.