|
Boost Users : |
From: Delfin Rojas (drojas_at_[hidden])
Date: 2005-04-30 15:19:53
> -----Original Message-----
> From: boost-users-bounces_at_[hidden] [mailto:boost-users-
> bounces_at_[hidden]] On Behalf Of David Abrahams
> Sent: Saturday, April 30, 2005 5:36 AM
> To: boost-users_at_[hidden]
> Subject: [Boost-users] Re: How to get type given pointer to base?
>
> "Delfin Rojas" <drojas_at_[hidden]> 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 <class TMappedObject, class TAttributeType, TAttributeType
(TMappedObject::*tfGetter)() const, void (TMappedObject::*tfSetter)(const
TAttributeType &)>
class CAttributeMapper
{
...
TAttributeType getAttributeValue(const TMappedObject & p) const {
return (p.*tfGetter)(); }
void setAttributeValue(const TAttributeType & value, const
TMappedObject & p) const { return (p.*tfSetter)(value); }
...
};
The "oject mapper" looks something like:
template<class TMappedObject, class TMappedObjectAllocator = std::allocator<
TMappedObject> >
class CObjectMapper
{
...
};
//Declare a mapped object
class A
{
public:
int getAge() const { return m_age; }
void setAge(const int & age) { m_age = age; }
static const CObjectMapper<A> OM;
static const CAttributeMapper<A, int, &A::getAge, &A::setAge> AM;
};
At construction of the object mapper and attribute mapper they both get a
name (string) and some flags. Then the attribute mapper gets a pointer to
its object mapper and the object mapper gets pointers to its attribute
mappers.
The "object mapper" and "attribute mapper" are used later in the program to
refer to the class A - for example, to serialize/deserialize an object of
class A from a database or XML. Particularly when deserializing, the code
only receives the "object mapper" A::OM above. Then the code must get all
the "attribute mappers" in this "object mapper" (A::AM in this case) and
call setAttributeValue in those "attribute mappers" which would call the
right "setter method" inside A (setAge in this case). As you see above the
setAttributeVale method in CAttributeMapper is templated so it would only
receive a value of the right type.
The part I cannot get to work is to have a collection of CAttributeMapper
objects inside CObjectMapper, and this is where my original question about
Foo<U> came from. How to get several objects of different types in the same
collection and retrieve them later and use them based on their type?
I hope I did not extend too much into details.
Thanks
-delfin
> --
> Dave Abrahams
> Boost Consulting
> www.boost-consulting.com
>
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net