0

I am trying to make a class that has a type that is decided by whatever type is passed to another class. Here is an example with all the unrelated stuff removed:

class foo_list{
private:
    std::list<foo_template>list;
public:
    template<class t>
    void addToList(t data,(something else unrelated)){
         list.push_back(new task<t>(data));
    }
}
template<class t>
class foo_template{
private:
    t data
    someOtherStuffThatIsUnrelated
   .
    .
     .
}

However something like this doesnt compile. Mainly because a template without a fixed type cant be used as a type for another template (or anything really).

What is the (correct) way to implement such a thing, preferrably with either full type information retained or a way to cast back to the original type.

MoustacheSpy
  • 743
  • 1
  • 6
  • 27

1 Answers1

2

The most straight-forward approach would make use of virtual functions. As you only hold a list of pointers without any further type information, it has to be kept and accessed at runtime some way.

#include <iostream>
#include <list>
#include <memory>
#include <string>

class Base {
public:
    virtual void bar() const = 0;
};

template <typename T>
class Foo_template : public Base {
    T t;
public:
    Foo_template(const T& tt) : t(tt) { }
    void bar() const override {
        std::cout << t << '\n';
    }
};

class Foo_list {
    std::list<std::unique_ptr<Base>> list;

public:
    template <typename T>
    void add_to_list(T&& data) {
        auto ptr = std::make_unique<Foo_template<T>>(std::forward<T>(data));
        list.push_back(std::move(ptr));
    }

    void bar_all() {
        for(auto& elem : list) elem->bar();
    }
};

int main() {
    Foo_list list;
    list.add_to_list(2);
    list.add_to_list(std::string{ "Hello, World!" });
    list.bar_all();
}

https://ideone.com/4qY0sK

Some additional thoughts: Do not use raw pointers for storing dynamically allocated memory but rather one of the smart pointers that suits your needs. Also, are you sure about your choice of std::list? In most circumstances, std::vector<> is the better choice. See for example here:
vector vs. list in STL
Relative performance of std::vector vs. std::list vs. std::slist?

Jodocus
  • 7,493
  • 1
  • 29
  • 45
  • I have a question: How can I acess the DATA member from the task? Do I just return the DATA with type t? If so how can I actually return it without loosing the type information? Also about the vector thing. I want to be able to resort the list as quickly as possible. I think a classic doubly linked list is better for that? – MoustacheSpy Sep 16 '17 at 19:54
  • Why would you want to do this? This pretty much breaks the principle of encapsulation. You should rather ask yourself why you want to group different unrelated types together and which operations they shall have in common. In my example, they all are printable. – Jodocus Sep 16 '17 at 20:05
  • About the sorting lists issue: https://stackoverflow.com/questions/8481234/performance-gap-between-sorting-a-list-and-a-vector-of-structs-c Long story short: vector is faster. – Jodocus Sep 16 '17 at 20:06
  • I dont mean "acess" as in directly acess the member but implement get and set methods, which can be used using the stuff in the vector.. – MoustacheSpy Sep 16 '17 at 20:29
  • Check out the link given above your question. You may achieve your goal by using std::variant or std::any. – Jodocus Sep 16 '17 at 20:37
  • So std::any is like void pointers in c++... That still doesnt answer my question. How can I have templated classes like this even interact with my program (without std::any. Using the wrapper class you suggested). Also is there a way to store the original type to use with std::any_cast (to regain the original data from the templated class) – MoustacheSpy Sep 16 '17 at 20:45
  • You would not use templates any longer, just a std::vector. Anyways, you really should reconsider your design. Why do you want to store seemingly totally uncorrelated types into one container? If you cannot even specify a common interface (which would be virtual), you are left to RTTI which is almost always considered as bad practise. Having getters and setters already cracks your encapsulation. Adding RTTI spoils your type safety. This way, you basically sacrifice a big chunk of C++ and OO benefits. – Jodocus Sep 16 '17 at 21:02
  • I will level with you here. I came from C and I have a rather old approach to things that I am trying to get rid of. Anyways. Here is what I want to do: I want a class called task that can hold onto data necessary to call a function of any class that is provided and has it (always called task_process).Also I want to have another class that automatically sorts the tasks by priority and then automatically runs once every loop.It goes through all tasks in its vector and calls the approperate function, passing the task to the member function. – MoustacheSpy Sep 16 '17 at 21:57
  • Also I am marking your post as the correct answer cause it did answer the original question – MoustacheSpy Sep 16 '17 at 22:02