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?
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.
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?
#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.
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.
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.
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!
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.
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.
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>
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.