The problem I need to solve is: create a multitude of Stacks with different types of data.

And what makes it difficult for me is the following: In the multitude there should be all sorts of data stacks. Would it be stacks with integers, chars, objects from user defined classes or whatever. Thus just normal Struct won't help me.

I'm thinking I should use an array of void pointers (void *) but then I get the "is not a pointer-to-object type" message. Until now all I've managed to do is to store the address of the different typed objects. I also thought about pointers to functions in the Stack that would convert the void pointers into pointers I can use ( with dynamic_cast or the (type *) ). However both don't do the trick - still not an object type pointer. Without the <type> for the templated stack I can't think of anything to do.

Putting any code would be useless as all I have a normal templated stack. My question is more kind of: Is there any trick to do it overriding the templates of the different typed stacks? And in general is it even possible to solve this problem?

Sorry if theres another topic with the same question - I do looked hard to find such yet nothing.

Dani AI

Generated

The core issue from is not creating individual typed stacks (templates do that) but holding them together at runtime in one container. As hinted, templates give you the concrete stack types, but you still need type erasure or a non-templated interface to store different specializations in one vector/array. 's note about dynamic languages is valid — they avoid static typing — but in C++ a few safe patterns work well.

One practical pattern is a small non-templated interface plus a templated implementation that uses std::any for type-erased element exchange. The container holds std::unique_ptr to the interface; each concrete StackImpl<T> owns a std::stack<T>. Pushing/popping goes through std::any and std::any_cast<T>. To recover a typed stack when you do know the type, dynamic_cast to StackImpl<T>* works because the interface is polymorphic.

// sketch: IStack + StackImpl<T>, store in vector<unique_ptr<IStack>>
struct IStack {
  virtual ~IStack() = default;
  virtual void push_any(const std::any&) = 0;
  virtual std::any top_any() const = 0;
  virtual void pop() = 0;
  virtual size_t size() const = 0;
};

template<typename T>
struct StackImpl : IStack {
  std::stack<T> s;
  void push_any(const std::any& a) override { s.push(std::any_cast<T>(a)); }
  std::any top_any() const override { return s.top(); }
  void pop() override { s.pop(); }
  size_t size() const override { return s.size(); }
};

Notes, alternatives and cautions:

  • std::any (C++17) and std::any_cast are the safe, modern choice; pre-C++17 use boost::any (, std::any).
  • dynamic_cast requires a polymorphic base (see dynamic_cast docs).
  • If the set of possible element types is closed and known, prefer std::variant for better safety/performance.
  • Avoid void* for ownership and type-safety reasons.
  • To expose one stack per type at runtime, use a unordered_map<std::type_index, unique_ptr<IStack>> keyed by typeid(T) (type_index).

Recommended Answers

All 5 Replies

C++ Templates is the key

Using multiple templates would solve my problem if I knew what would go in the multitude. Please give me a better hint if I'm wrong.

having re-read the thread, i realize that my earlier post was asinine.
perhaps you should consider using a programming language that is not statically typed (ideally with some support for reflective programming).

having re-read the thread, i realize that my earlier post was asinine.
perhaps you should consider using a programming language that is not statically typed (ideally with some support for reflective programming).

You have a point. Thank you for the idea.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.