0

So, as you might have already imagined, I'm trying to use wildcards in C++. But first, let me give you an example of what I mean: Lets suppose we have a Human class and a Pocket class. The Pocket class has an arbitrary other class as an type argument. To visualize this better, let's write some code (in Java:)

Human.java:

package de.budschie.human_pocket_example;

import java.util.ArrayList;

public class Human 
{
    ArrayList<Pocket<?>> inventory = new ArrayList<>();
}



Pocket.java:

package de.budschie.human_pocket_example;

public class Pocket<E>
{
    E pocketElement;
    int amount;
    
    public Pocket(E pocketElement, int amount) 
    {
        this.pocketElement = pocketElement;
        this.amount = amount;
    }
    
    public E getPocketElement() 
    {
        return pocketElement;
    }
    
    public int getAmount() {
        return amount;
    }
}



As you can see, I can store pockets, regardless of their type argument. I could create a pocket which contains a pocket which contains an Integer, and an other pocket, which contains a Float, and both would fit into the inventory. So, my question is:

How would I do that in C++?

I already tried to use the question mark, but that doesn't seem to have worked. I can't just say, that I want an std::vector<Pocket<?>>.

I hope that this is not off-topic for StackOverflow, and if it is, please tell me in the comments and I'll delete this question as soon as I am able to.

Budschie
  • 32
  • 6
  • Can you show your c++ code and what is not working for you? How are you trying to use it? `template void foo(std::vector> vec) {}` can support any `Pocket`. – clcto Feb 04 '21 at 14:09
  • I would suggest picking up [a good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). What you want to do will be explained there as "templates". – AVH Feb 04 '21 at 14:21

2 Answers2

1

You have three key differences between Java and C++ to cope with here: the type system is different, templates are not generics, and vectors are not arraylists.

  1. The type system:

    In Java, every instantiation of Pocket<E> still derives from Object, so there's some common base type to store a reference to.

    In C++, every instantiation of Pocket<E> is a distinct type, and there is no implicit inheritance of a root type. If you want every Pocket<E> to derive from something, you have to do that manually.

  2. The type system again:

    Say you add a root for your hierarchy, PocketBase, from which which every Pocket<E> derives. Since there is no root type, there's also no common base class for the different E types, and hence no common return type for the different Pocket<E>::getPocketElement().

    You can just have it return std::any, I guess, if that makes sense. But then you could just use std::any in PocketBase directly, because Pocket<T> isn't doing any more than that.

  3. std::vector stores objects. If you want polymorphism, you need to store pointers instead. Again, you need to do this explicitly: std::vector<std::unique_ptr<PocketBase>> or whatever.

The basic hierarchy is something like this:

class PocketBase
{
protected:
  int amount_ = 0;

public:
  virtual ~PocketBase() = 0;

  int amount() const { return amount_; }
};

template <typename T>
class Pocket: public PocketBase
{
  T element_;
public:
  // etc. etc.
};

And now

std::vector<std::unique_ptr<PocketBase>>

can store (pointers to) any mixture of Pocket<T> types.

Useless
  • 64,155
  • 6
  • 88
  • 132
1

I'd suggest making Pocket a non-template class and keep one std::any attribute inside to store any type of value.

    struct Human {
        struct Pocket {
            std::any thing; 
            std::size_t quantity;
        };
        std::vector<Pocket> pockets;
    };
m88
  • 1,968
  • 6
  • 14