3

Consider the following example:

class MyContainer {
    std::vector<void *> v;
public:
    void Put(void *x) { v.push_back(x);}
    void* Get(int index) { return v[index];}
};

void Work (MyContainer& c) {
    // cast_to_type(c.Get(0));
}

int main() {
    int x = 1;
    double y = 2.0;
    MyContainer c;
    c.Put(&x);
    c.Put(&y);

    Work(c);

    return 0;
}

Assume that function Work knows nothing about the objects to which vector pointers point to. Also assume that inheritance is not an option and that types of the pointed objects can be arbitrary (there can be infinite number of types).

Is it possible to deduce the type using only the void pointer returned by MyContainer::Get function? Can this be done using any combination of casts, templates and typeid operator?

Diggy
  • 230
  • 2
  • 11
  • 6
    Short answer: no. – Chris Lutz Mar 01 '12 at 02:56
  • What if I use templates to wrap objects, and then put pointers to wrapped objects? Can I use templates to somehow save the information about the type? – Diggy Mar 01 '12 at 03:06
  • @Diggy: Not directly, but you can now apply inheritance through this wrapper. See [`boost::any`](http://www.boost.org/doc/libs/1_49_0/doc/html/any.html). – Xeo Mar 01 '12 at 03:07
  • @Diggy - Yes, but then you're not really using `void *` pointers. `void *` implies that it can point to literally anything. And anyway, any template solution you use will end up reinventing `boost::any` or something similar. – Chris Lutz Mar 01 '12 at 03:08

1 Answers1

9

No, void*s have absolutely no information associated with them whatsoever, and when you cast a pointer to a void*, you lose the type completely. You'll have to find another way to store different types in the same container, such as with inheritance.

You could also do something like this:

class MyContainer {
    struct cont {
        void* ptr;
        type_info* ti; // pointer, not reference, so this struct can be copied
    };

    std::vector<cont> v;

public:
    template<typename T>
    void Put(T* x) {
        v.push_back({ x, &typeid(T) });
    }

    // do whatever you want with Get using *v[x].ti
};

int x = 1;
double y = 2.0;
MyContainer c;
c.Put(&x);
c.Put(&y);

Work(c);

But I don't know how much help that would be without knowing what you are trying to do. You might have to resort to something a little more advanced like boost::any.

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • You were faster than my edit :). What if inheritance is impossible. – Diggy Mar 01 '12 at 03:03
  • Unfortunately, I can't use type_info to recast my void pointer to a proper type. See [Typecasting_with_type_info](http://stackoverflow.com/questions/4972795/typecasting-with-type-info). So this still is not a solution to my question. – Diggy Mar 01 '12 at 18:22
  • @Diggy then unfortunately there is no solution; C++ doesn't have the facilities to do what you want (aside from, as I said, using something like `boost::any`). Perhaps if you could tell us what you're trying to do? – Seth Carnegie Mar 01 '12 at 22:56
  • Thanks for the answer Seth. `boost::any` doesn't really solve this problem either. It does enable storing different objects into a single container, i.e. std::vector, which is good. Additionally, it provides support for casting encapsulated object into the proper type, though again you have to know the type to call casting methods. It seems that there is no solution to this question, so even though your answer is useful, I cannot accept it as a definite answer. – Diggy Mar 05 '12 at 19:00
  • 1
    @Diggy actually, although there is no solution, there is definitely an answer, which is "you can't do it", which is what my answer says. And I might be able to help more if you told me what exactly you want to do. – Seth Carnegie Mar 05 '12 at 20:40