6

I have got two classes.

The first class (A) is builded with an template.

template <class T>
class A
{
    public:
        T value;
};

The second class (B) should have an object of class A as member variable. Like this:

class B
{
    public:
        A<int> value;
};

But now i want to use any kind of template-class in class A. Not only int. Apparent I can't declare a (member-)variable which contains any kind of a class. So, I need something like this:

class B
{
    public:
        A<*> value;
};

Is there any (clean) solution for this problem?

-- Greeting from Germany, Bastian

user906756
  • 61
  • 1
  • 1
  • 2
  • 1
    Why do you need such a thing? [Describe the goal, not the step](http://www.catb.org/esr/faqs/smart-questions.html#goal). – GManNickG Aug 22 '11 at 23:02

5 Answers5

7

You cannot have a single class B with "any" member object, because B has to be a well-defined class, and A<T> is a different type for different types T. You can either make B a template itself:

template <typename T>
class B
{
  A<T> value;
};

or you can take a look at boost::any, which is type-erasing container for arbitrary types (but making use of it requires a certain amount of extra work). The any class only works for value types, though, it's not completely arbitrary.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • "type-erasing"? really? how does `any_cast` work without type? – Nim Aug 22 '11 at 23:08
  • @Nim: "type-erasing" in the sense that the type of the `any` object does not depend on the type of the things you put in. Compare to `shared_ptr`, which can be constructed with a custom deleter or custom allocator, neither of which become part of the type. – Kerrek SB Aug 22 '11 at 23:10
  • @Nim: A tell-tale for a type-erasing class is a private nested polymorphic class from which templated subclasses are derived. Take a look at `any.hpp`, that's what's going on (called `placeholder`). – Kerrek SB Aug 22 '11 at 23:15
  • @Nim: [See this answer](http://stackoverflow.com/questions/6122094/building-boostoptions-from-a-string-boostany-map/6123962#6123962). – GManNickG Aug 23 '11 at 20:19
4

The simplest solution would be to make all A variants ineherit from a common interface, even if it's empty :

class IA{}

template <class T>
class A : public IA
{
    public:
        T value;
};

class B
{
    public:
        IA* value;
};

Now, the associated costs:

  • interactions with value are limited to the IA interface;
  • if you try to cast to get the real type, that mean that you know the real type, so it's of no use and make A type a parameter of B becomes really easier to use.
  • there are runtime costs associated to runtime inheritance

Advantage :

  • it's easily understood by other developers
  • it naturally limit the types possible to some specific ones
  • it don't use boost (sometimes, you just can't)

So to do better there are other less simple solutions but that are simple enough to be used :

If you can use boost, boost::any, boost::variant and boost::mpl might be base of solutions.

Boost any can be used as a safe replacement to void*. The only problem with this is that you can have ANY type, like if the type was a template parameter of the B class.

Boost variant might be used successfully if you know all the types that A can be.

MPL might be helpful if you just want to set a list of possible types and make sure your members apply only to them. You can do a ton of things with MPL so it really depends on your exact needs.

Klaim
  • 67,274
  • 36
  • 133
  • 188
2

You've got two choices, I think. The first is to parameterize your class over the type parameters of the instance variables:

template <class T> struct B
{
  A<T> value;
};

The other option is to declare value as a void* pointer. (But that's probably not what you want).

Jonathan Sterling
  • 18,320
  • 12
  • 67
  • 79
1

yes, it's already been done. boost::any.

Nim
  • 33,299
  • 2
  • 62
  • 101
1

I think it helps to understand, that templated classes create an entirely new and seperate class for every type you use with it. For instance, Vector<int> and Vector<float> are as separate as the classes VectorInt and VectorFloat.

For class B, you are basically asking that the value variable either be A<int> or A<float>, which is the same as saying you want value to either be a "A_int" or "A_float". And to accomplish that you... well, use another template!

Anne Quinn
  • 12,609
  • 8
  • 54
  • 101