How to get type given pointer to base?
Hello all, I hope somebody can help me with this. What I want to do is the following: Let's say I have a templated class called Foo template<class U> class Foo { public: Foo(U * p) : m_p(p) {} ~Foo() {} U* getP() const { return m_p; } private: U* m_p; }; Now let's say I want to have a collection of pointers to Foo. What should I do? The possibilities I can think of are the following: 1) Create a class FooBase and have Foo inherit from FooBase. FooBase is non-templated so there should be no problem with having a collection of pointers to FooBase where I can put instances of Foo. The problem with this approach is that given a FooBase* in that collection I could not use the getP method because I would not know what type of Foo it holds. 2) Create a boost::variant of all the possible types of Foo<U>* I want to have. Then have a collection of this FooVariant. Using static visitation I can obtain the original type of Foo<U>* in a given FooVariant. The problem with this approach is that I get an ICE from VC++ 7.1 when the type of U gets too complex (shared_ptr to another type for example). Have I overlooked something? Is there a better technique for what I want to achieve? Any help would be great, Thanks Delfin Rojas
On 4/30/05, Delfin Rojas
Hello all,
I hope somebody can help me with this. What I want to do is the following:
Let's say I have a templated class called Foo
template<class U> class Foo { public: Foo(U * p) : m_p(p) {} ~Foo() {} U* getP() const { return m_p; } private: U* m_p; };
Now let's say I want to have a collection of pointers to Foo. What should I do? The possibilities I can think of are the following:
1) Create a class FooBase and have Foo inherit from FooBase. FooBase is non-templated so there should be no problem with having a collection of pointers to FooBase where I can put instances of Foo. The problem with this approach is that given a FooBase* in that collection I could not use the getP method because I would not know what type of Foo it holds.
2) Create a boost::variant of all the possible types of Foo<U>* I want to have. Then have a collection of this FooVariant. Using static visitation I can obtain the original type of Foo<U>* in a given FooVariant. The problem with this approach is that I get an ICE from VC++ 7.1 when the type of U gets too complex (shared_ptr to another type for example).
Have I overlooked something? Is there a better technique for what I want to achieve? Any help would be great,
Thanks
Delfin Rojas
Using the first method, you could use something like this: class FooBase { public: template<class T> T* getP() const { return IsSameType(typeid(T*))?(T*)RawPointer():(T*)0; } private: virtual bool IsSameType(std::type_info const& ti) const = 0; virtual void* RawPointer() const = 0; }; template<class U> class Foo : public FooBase { public: Foo(U * p) : m_p(p) {} ~Foo() {} private: U* m_p; virtual bool IsSameType(std::type_info const& ti) const { return 0!=(ti == typeid(U*)); } virtual void* RawPointer() const { return (void*)m_p; } }; In the following fragment Foo<int> blah(new int); int* pInt = blah.getP<int>(); char* pChar = blah.getP<char>(); pInt is non-zero, pChar is zero because char != int. Stuart Dootson
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of Stuart Dootson Sent: Saturday, April 30, 2005 2:55 AM To: boost-users@lists.boost.org Subject: Re: [Boost-users] How to get type given pointer to base?
Hello all,
I hope somebody can help me with this. What I want to do is the following:
Let's say I have a templated class called Foo
template<class U> class Foo { public: Foo(U * p) : m_p(p) {} ~Foo() {} U* getP() const { return m_p; } private: U* m_p; };
Now let's say I want to have a collection of pointers to Foo. What should I do? The possibilities I can think of are the following:
1) Create a class FooBase and have Foo inherit from FooBase. FooBase is non-templated so there should be no problem with having a collection of pointers to FooBase where I can put instances of Foo. The problem with
approach is that given a FooBase* in that collection I could not use the getP method because I would not know what type of Foo it holds.
2) Create a boost::variant of all the possible types of Foo<U>* I want to have. Then have a collection of this FooVariant. Using static visitation I can obtain the original type of Foo<U>* in a given FooVariant. The
On 4/30/05, Delfin Rojas
wrote: this problem with this approach is that I get an ICE from VC++ 7.1 when the type of U gets too complex (shared_ptr to another type for example).
Have I overlooked something? Is there a better technique for what I want to achieve? Any help would be great,
Thanks
Delfin Rojas
Using the first method, you could use something like this:
class FooBase { public: template<class T> T* getP() const { return IsSameType(typeid(T*))?(T*)RawPointer():(T*)0; } private: virtual bool IsSameType(std::type_info const& ti) const = 0; virtual void* RawPointer() const = 0; };
template<class U> class Foo : public FooBase { public: Foo(U * p) : m_p(p) {} ~Foo() {} private: U* m_p; virtual bool IsSameType(std::type_info const& ti) const { return 0!=(ti == typeid(U*)); } virtual void* RawPointer() const { return (void*)m_p; } };
In the following fragment
Foo<int> blah(new int);
int* pInt = blah.getP<int>(); char* pChar = blah.getP<char>();
pInt is non-zero, pChar is zero because char != int.
Stuart Dootson
Yes, that would _work_ but unfortunately the code that need to call getP would have to call it with every possible type and check if the return is zero. Ideally I would like the following: FooBase * pB = new Foo<int>(new int); ... int * pI = pB->getP(); //compiles char * pChar = pB->getP(); //does not compile -delfin
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
"Delfin Rojas"
pInt is non-zero, pChar is zero because char != int.
Stuart Dootson
Yes, that would _work_ but unfortunately the code that need to call getP
Please limit the amount of text quoted in your replies. -- Dave Abrahams Boost Consulting www.boost-consulting.com
"Delfin Rojas"
Hello all,
I hope somebody can help me with this. What I want to do is the following:
Let's say I have a templated class called Foo
template<class U> class Foo { public: Foo(U * p) : m_p(p) {} ~Foo() {} U* getP() const { return m_p; } private: U* m_p; };
Now let's say I want to have a collection of pointers to Foo. What should I do? The possibilities I can think of are the following:
1) Create a class FooBase and have Foo inherit from FooBase. FooBase is non-templated so there should be no problem with having a collection of pointers to FooBase where I can put instances of Foo. The problem with this approach is that given a FooBase* in that collection I could not use the getP method because I would not know what type of Foo it holds.
Not knowing what type of Foo it holds, how would you know what to do with the result of getP? Its type depends on the type of the Foo. If you are willing to just get a void*, type erasure (see http://www.boost.org/doc/html/signals/s05.html#id574178 and http://www.boost-consulting.com/mplbook) might help. Otherwise...
2) Create a boost::variant of all the possible types of Foo<U>* I want to have. Then have a collection of this FooVariant. Using static visitation I can obtain the original type of Foo<U>* in a given FooVariant. The problem with this approach is that I get an ICE from VC++ 7.1 when the type of U gets too complex (shared_ptr to another type for example).
Have I overlooked something? Is there a better technique for what I want to achieve? Any help would be great,
You could store them in shared_ptr<void>, or use boost::any. -- Dave Abrahams Boost Consulting www.boost-consulting.com
-----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users- bounces@lists.boost.org] On Behalf Of David Abrahams Sent: Saturday, April 30, 2005 5:36 AM To: boost-users@lists.boost.org Subject: [Boost-users] Re: How to get type given pointer to base?
"Delfin Rojas"
writes: Hello all,
I hope somebody can help me with this. What I want to do is the following:
Let's say I have a templated class called Foo
template<class U> class Foo { public: Foo(U * p) : m_p(p) {} ~Foo() {} U* getP() const { return m_p; } private: U* m_p; };
Now let's say I want to have a collection of pointers to Foo. What should I do? The possibilities I can think of are the following:
1) Create a class FooBase and have Foo inherit from FooBase. FooBase is non-templated so there should be no problem with having a collection of pointers to FooBase where I can put instances of Foo. The problem with this approach is that given a FooBase* in that collection I could not use the getP method because I would not know what type of Foo it holds.
Not knowing what type of Foo it holds, how would you know what to do with the result of getP? Its type depends on the type of the Foo.
Yes, what I do with the result of getP would depend on the type of U. That is why I would need to get the right Foo<> back from FooBase *. Then I would pass this Foo<> through a template function that is specialized to a specific U and knows what to do with the result of getP(). That is why I thought on boost::variant, because the concept of static visitation seems to cover this problem. Namely, if I have a variant with different Foo<> then I can apply a visitor on this variant and each operator() in the visitor would get the right Foo<U>. Of course, to declare such variant I would need to know all the possible Foo<U> I would have but still this is OK. The problem is when I tried this I got an ICE.
If you are willing to just get a void*, type erasure (see http://www.boost.org/doc/html/signals/s05.html#id574178 and http://www.boost-consulting.com/mplbook) might help. Otherwise...
I have been looking at MPL but it seems to me MPL collection objects can store types, and integral constants but not instances of objects. I will look into boost::signal and their type erasure concept. Thanks for the pointer.
2) Create a boost::variant of all the possible types of Foo<U>* I want to have. Then have a collection of this FooVariant. Using static visitation I can obtain the original type of Foo<U>* in a given FooVariant. The problem with this approach is that I get an ICE from VC++ 7.1 when the type of U gets too complex (shared_ptr to another type for example).
Have I overlooked something? Is there a better technique for what I want to achieve? Any help would be great,
You could store them in shared_ptr<void>, or use boost::any.
Yes, I can store them in shared_ptr<void> or use boost::any but when I want
to get the right Foo<U> back I would need to know what to cast the _void_ or
the _any_ to.
Perhaps I should illustrate the more specific problem I'm trying to solve.
Imagine a database mapping system. There is an "object mapper" that is
"linked" to a class and there are "attribute mappers" that are linked to a
"get" and "set" methods in that class. The "object mapper" must hold a
collection of the "attribute mappers" in its class.
What I wanted was to set up this mapping at compile time. Namely, the
"attribute mapper" could have a template signature as follows:
template
-- Dave Abrahams Boost Consulting www.boost-consulting.com
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
"Delfin Rojas"
Not knowing what type of Foo it holds, how would you know what to do with the result of getP? Its type depends on the type of the Foo.
Yes, what I do with the result of getP would depend on the type of U. That is why I would need to get the right Foo<> back from FooBase *. Then I would pass this Foo<> through a template function that is specialized to a specific U and knows what to do with the result of getP().
In that case you're erasing the type information too early. You need
to instantiate the function template you mention above (call it f)
before you lose the type of Foo, e.g. make a vector of
shared_ptr<FooHolderBase>:
template <class T> void f(T*);
struct FooHolderBase
{
virtual ~FooHolderBase() {}
virtual void do_something_with_getP() = 0;
};
template <class U>
struct FooHolder
{
FooHolder(Foo<U> const& x) : held(x) {}
void do_something_with_getP()
{
f(held.getP()); // <== f gets instantiated
}
Foo<U> held;
};
template <class U>
void add_foo(
std::vector
...
In that case you're erasing the type information too early. You need to instantiate the function template you mention above (call it f) before you lose the type of Foo, e.g. make a vector of shared_ptr<FooHolderBase>:
<snip code>
There are various other ways to write this basic idiom (e.g. using function pointers instead of building a class with virtual functions), but the essential thing is that f<U> gets instantiated when you still know U at compile-time.
If you try to erase the type first, you will end up with what is essentially a massive type-switch:
type_info dynamic_type = typeid(*some_foo_base_ptr); if (dynamic_type == typeid(Foo<A>)) f(*dynamic_cast
(some_foo_base_ptr)); else if (dynamic_type == typeid(Foo<B>)) f(*dynamic_cast (some_foo_base_ptr)); ... which really sucks because it has to be maintained every time you write Foo<U> for some new U.
Thanks for the advice. Yes, that dynamic_cast switch was precisely what I as trying to avoid and I think I can avoid it using what you suggested (instantiating template function when the type of the object is still known).
HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (3)
-
David Abrahams
-
Delfin Rojas
-
Stuart Dootson