Angus Comber
Angus Comber

Reputation: 9708

Templated classes, how to represent as a member variable of another class without making this class templated

I have a templated class,

template<typename T>
class TClass
{
public:
   //functions here
};

class Holding {
  public:

 private:
  TClass<T>  m_item;  //don't want this
};

int main() {
   Holding hd;
   //do whatever
   return 0;
}

I want a sort of instance variable in Holding but don't want to make Holding a template class. What are my design options?

Upvotes: 2

Views: 71

Answers (4)

pmr
pmr

Reputation: 59811

You can use type-erasure if the possible holdings are similar enough.

#include <memory>

class HeldType {
public:
  virtual void myfunc() = 0;
  virtual ~HeldType() {}
};

template<typename T>
class HeldTypeModel : public HeldType {
public:
  HeldTypeModel(const T& t) : data_(t) {}
  void myfunc() { data_.myfunc(); }
private:
  T data_;
};

class TClass {
public:
  TClass() : x_(nullptr) {}

  template<typename T> 
  void set_t(const T& t) {
    x_.reset(new HeldTypeModel<T>(t));
  }

  std::unique_ptr<HeldType> x_;
};

class model {
public:
  void myfunc() {}
};

int main()
{
  TClass x;
  x.set_t(model{});
  return 0;
}

You need to figure out what are the commonalities between all the possible T. You probably also want to add some functions to get the typeid and to cast out the actual type etc. Have a look at boost::any.

If you are more on the experimental side of things, you can have a look at Boost.Type Erasure, which takes away some of boiler-plate, but is not yet part of an official release.

Upvotes: 0

emartel
emartel

Reputation: 7773

I might not understand your question properly. Basically, you have a template class TClass which needs to be configured through a template parameter. You then have Holding which owns a TClass but you don't want to make Holding a template for whatever reason.

This means that Holding needs to statically define what's the template parameter

TClass<SomeClass> m_item;

Now, you say in code you don't want this... I'm not sure if you don't want to provide a template parameter or provide T. If it's T, the code above would fix your issue. Otherwise, you'll need to use a typedef to remove the template argument and have a "template-less" type, such as:

typedef TClass<int> intTClass; // replace int by whatever param you want

which can then be used as

class Holding {
  public:

 private:
  intTClass m_item;  //don't want this
};

Upvotes: 0

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361582

It looks like you want to hold any type. If that is really the case, then you could use boost::any:

class Holding {
  public:

 private:
  TClass<boost::any>  m_item;  //you want this?
};

If you don't use Boost, then you could implement any yourself or search for its implementation on this site or use google.

Upvotes: 2

Derive TClass from a non-template base class B and have Holding hold a pointer (perhaps std::unique_ptr) to B.

Upvotes: 1

Related Questions