1

Introduction

Say I have the follow

class thing {
    template<typename T> void method(T value) {}
}

What I want to do is to store whatever value is passed into value no matter what type into a std::vector or something and without turning this into a template class (because that doesn't solve my problem in anyway)

I want to be able to do this without using boost (as much i love boost i am not going to use it all the time)

Attempted Ideas

Void Pointer

My initial though is to use a void* however i would lose the type of the object and it could end up being unsafe.

Union/Struct

My next thought was to use a union/struct like the one below:

union type_wrapper {
    int a;
    char f;
/* etc, etc, etc */
}

However i would run into the same problem as I would have to track the type, so i make sure it remains the same when ever used.

Wrapper Class

Then next thing i attempted was a class that would return the type in a function call like so:

template<typename T> 
class type_wrapper {
    T getType() { return /* get value of type/pointer/object here */ }
    /*Stored in some manner */
}

Problem with is the same thing as with just the type on its own in that it cannot be stored in a list called lets say std::list<AClass> when its of type std::list<BClass> or std::list<int> etc

Other thing

All other examples i have looked at have do what i am doing but are expect that you track the type of the object one way or another, or use boost.

tl;dr

What could i try doing so that i could pass a parameter of type int and storing into a std::list etc it while using the same template function to pass a parameter of type 'cheese' (an imaginary class dedicated to filling your programs with cheese) and storing it into the same list, etc

Community
  • 1
  • 1
TheKingOfAtlantis
  • 1,792
  • 2
  • 12
  • 18

1 Answers1

2

I don't know if this will solve your problem, but you can use some polymorphic type for the container, and encapsulate the object in a generic derived class, so calls to object's member functions from the derived class' member functions can have full type information (they will be specialized templates), but your "thing" won't be generic, and client code won't care (or even know) about this inhertance:

class Aux {
public:
    virtual void DoSomething() =0 ;
};

template<typename T>
class AuxTemp : public Aux {
    T *real_obj;
public:
    AuxTemp(const T &obj) : real_obj(new T(obj)) {} // create
    AuxTemp(const AuxTemp &other) : real_obj(new T(*other.real_obj)) { } // copy
    AuxTemp(AuxTemp &&other) : real_obj(other.real_obj) { other.real_obj=nullptr; } // move
    ~AuxTemp() { delete real_obj; } // destroy
    void DoSomething() override { 
        real_obj->DoSomething(); // here we call the method with full type information for real_obj
    }
};

class Thing {
    std::vector<Aux*> v;
public:
    template<typename T> void Add(const T &value) {
        v.push_back(new AuxTemp<T>(value));
    }
    void DoSomethingForAll() { 
        for(auto &x:v) x->DoSomething();
    }
};

Yo can test this with:

class A {
public:
    void DoSomething() { std::cout << "A"<< std::endl; }
};

class B {
public:
    void DoSomething() { std::cout << "B"<< std::endl; }
};

int main(int argc, char *argv[]) {
    Thing t;
    t.Add(A{});
    t.Add(B{});
    t.DoSomethingForAll();
    return 0;
}

For each new type you push to your vector, a new derived and specialized wrapper class is made by Add member function, so virtual table can handle calls to DoSomething in order to use the proper and full-aware-of-real-type version.

I think what I propose is a bizarre implementation "type-erasure" (you should google for this term to find more elaborated solutions).

Zaskar
  • 569
  • 3
  • 10