1

So I have these classes:

class Base {

};
template <typename T>
class Derived<T>: public Base {

};

class util {
    public:
        template <typename T>
        void add(Derived<T> arg) {
           vec.push_back(arg);
        } 
        
        void start() {
            //cast back down to Derived<T>
        }
  
   private:
       std::vector<Base> vec;
};

In start() I want to cast it back down to Derived<T> but since the T can be anything, I can't cast it without the type. I'm wondering if there was to store the first element of vec's type information in like a typedef or something so that I can use that in start()

Kit
  • 51
  • 8
  • 1
    Storing the `Derived`s in a `vector` *slices*: the `Base` subobject of `arg` is copied into `vec` and the rest of it is destroyed. `vec` *doesn't have* any `Derived` objects to downcast. So: 1) this is probably an XY problem; what are you actually trying to do? 2) If you go ahead with this, you probably need to store (smart) *pointers*, not objects, in the vector 3) See `std::type_info` and `std::any`. 4) You can't have a `Derived` without knowing what `T` is at compile time. Period. Perhaps type erasure is in order (look it up on SO, I'm out of characters). – HTNW Jul 10 '20 at 22:21
  • 1
    Maybe you were thinking of the [CRTP](https://stackoverflow.com/q/4173254/5987) but I don't think it applies in your case. – Mark Ransom Jul 10 '20 at 22:28

1 Answers1

1

First of all you have a syntax issue:

template <typename T>
class Derived<T>: public Base { // Won't compile, the class name is Derived, and it doesn't suppose to get specialized by T type
};

The right way:

template <typename T>
class Derived : public Base {};

For your issue, you don't need to convert it back to the derived type, you just need to make your vector a vector of pointers to Base class (and in the insertion function, accept the Derived type as a reference, to pass it's address to the vector).
Note: in the implementation you'll see that I passed a shared_ptr- it's to make the ownership of the address obvious, when you use shared_ptr instead of unsafe pointers in your vector (Thanks to @idclev463035818 for the note).

class util {
public:
    template <typename T>
    void add(std::shared_ptr<Derived<T>> arg) {
        vec.push_back(arg);
        // vec.push_back(&arg); // In case that you don't use shared_ptr, and pass arg by reference.
    }

    void start() {
        for (auto d : vec) { /* ...  */ }
    }

private:
    // Idea: std::vector<Base*> vec;
    std::vector<std::shared_ptr<Base>> vec; // For safe memory management
};
Coral Kashri
  • 3,436
  • 2
  • 10
  • 22
  • probably it should be a vector of smart pointers. In your code it isnt clear who own the elements in the vector and you cannot delete them in `util` because you cannot know whether it was dynamically allocated. `add` should take a smart pointer to make ownership obvious – 463035818_is_not_an_ai Jul 10 '20 at 22:28
  • @idclev463035818 I always recommend to use smart pointers, but I wanted to make the point here more clearer for the OP. But you are right, I added a note there. – Coral Kashri Jul 10 '20 at 22:33
  • Even with the shared pointers if Derived has some method, I cant call the method without casting it since Base doesnt have that method defined. – Kit Jul 10 '20 at 23:30
  • 1
    @Kit it's true, but if this is the case, it's probably an architecture issue. The base is an interface, which allows you to use Polymorphism. If you want just a collection of different types you should consider using variadic functions/templates. – Coral Kashri Jul 11 '20 at 00:20