templates & polymorphic classes

V

verec

One problem I've come accross in designing a specific version of auto_ptr
is that I have to disntiguish between "polymorphic" arguments and "plain" ones,
because the template has to, internally, cast to void *.

Specifically,
template <typename T> void f(T * t) {
void * p = dynamic_cast<void *>(t) ;
}

will not compile if T isn't of a class that has somewhere at least
a virtual function. In particular, none of the STL containers do qualify
for T.

Yet, because of multiple inheritance, if I want to get down to the base
"most" class, the dynamic_cast<void*> is the way to go.

I could use reinterpret_cast instead, and this would work for all T,
except that I'd lose the "cast to base" feature mentionned above.

I could also use a pair of templates, one for polymorphic types,
and one of "POD". But I'd rather not do that.

I'd be happy with a runtime query ... if I could devise one, that is.

typeid() seems to not be applicable in this context.

Ideally, if I could come up with

template <typename T>
bool is_polymorphic(T t) {
...
}

I would be filled with joy :)

Any taker?
 
R

Rolf Magnus

verec said:
One problem I've come accross in designing a specific version of auto_ptr
is that I have to disntiguish between "polymorphic" arguments and "plain"
ones, because the template has to, internally, cast to void *.

Specifically,
template <typename T> void f(T * t) {
void * p = dynamic_cast<void *>(t) ;
}

will not compile if T isn't of a class that has somewhere at least
a virtual function.

It won't ever work, because dynamic_cast only works within a class
hierarchy, and 'void' doesn't belong to it. It doesn't seem to make much
sense to me either. How and why would you want a dynamic_cast that would
attempt to check whether an object is derived from 'void'? Why not just
static_cast?
In particular, none of the STL containers do qualify
for T.

Yet, because of multiple inheritance, if I want to get down to the base
"most" class, the dynamic_cast<void*> is the way to go.

No. 'void' is not the base class.
I could use reinterpret_cast instead, and this would work for all T,
except that I'd lose the "cast to base" feature mentionned above.

I fail to see what you need that for.
I could also use a pair of templates, one for polymorphic types,
and one of "POD". But I'd rather not do that.

I'd be happy with a runtime query ... if I could devise one, that is.

What for?
 
V

verec

It won't ever work, because dynamic_cast only works within a class
hierarchy, and 'void' doesn't belong to it. It doesn't seem to make much
sense to me either. How and why would you want a dynamic_cast that would
attempt to check whether an object is derived from 'void'? Why not just
static_cast?

I'm sorry I didn't make myself clear enough. An actual example will
probably help. Consider:

template <typename T> struct my_ptr {
void * rawValue ;
my_ptr(T *t) : rawValue(dynamic_cast<void *>(t)) {
}
} ;

struct polymorphic {
virtual ~polymorphic() ;
} ;

struct pod {
} ;

typedef my_ptr<polymorphic> Poly ;
typedef my_ptr<pod> Pod ;

void
test_00005() {
Poly p(new polymorphic) ;
// Pod pp(new pod) ;
}

If I leave the "Pod pp" line commented out, everything compiles and works
fine. However, if I uncomment it, I get:


### error: cannot dynamic_cast 't' (of type 'struct pod*') to type 'void*'
### (source type is not polymorphic)

What I am after, is a way to define 'my_ptr' above so that it deals
correctly with both polymorphic and POD structs. The need for the
dynamic_cast in the case of "polymorphic" structs is because when
MI is used, dynamic_cast guarantees that you get a pointer back to
the base object, no matter what branch of the derivation has been
used for T.

If anything is still unclear, please, let me know.

All I want is a "write once, run anywhere" (TM :) template that I
can use all over the place, without having to ask first, "Am I dealing
with a pod or a poly?"

Many Thanks.
 
V

Victor Bazarov

verec said:
I'm sorry I didn't make myself clear enough. An actual example will
probably help. Consider:

template <typename T> struct my_ptr {
void * rawValue ;
my_ptr(T *t) : rawValue(dynamic_cast<void *>(t)) {

There is no need to use 'dynamic_cast' to convert a pointer to an object
to void*. It's convertible _implicitly_.
}
} ;

struct polymorphic {
virtual ~polymorphic() ;
} ;

struct pod {
} ;

typedef my_ptr<polymorphic> Poly ;
typedef my_ptr<pod> Pod ;

void
test_00005() {
Poly p(new polymorphic) ;
// Pod pp(new pod) ;
}

If I leave the "Pod pp" line commented out, everything compiles and works
fine. However, if I uncomment it, I get:


### error: cannot dynamic_cast 't' (of type 'struct pod*') to type 'void*'
### (source type is not polymorphic)

What I am after, is a way to define 'my_ptr' above so that it deals
correctly with both polymorphic and POD structs. The need for the
dynamic_cast in the case of "polymorphic" structs is because when
MI is used, dynamic_cast guarantees that you get a pointer back to
the base object, no matter what branch of the derivation has been
used for T.

To what base object? The pointer you store is 'void*'!
If anything is still unclear, please, let me know.

Hell, yes. Perhaps you could post the _real_ 'my_ptr' class.
All I want is a "write once, run anywhere" (TM :) template that I
can use all over the place, without having to ask first, "Am I dealing
with a pod or a poly?"

You should also try to show _how_ you're going to use an object of type
'my_ptr'. "I can use all over the place" is too vague a statement to be
of any value.

V
 
V

verec

There is no need to use 'dynamic_cast' to convert a pointer to an object
to void*. It's convertible _implicitly_.

Excellent! I just tried. And it works!

Many Thanks.
 
S

Swampmonster

[]
There is no need to use 'dynamic_cast' to convert a pointer to an object
to void*. It's convertible _implicitly_. []
To what base object? The pointer you store is 'void*'!

Actually he got it wrong, but not completely:

/dynamic_cast < type-id > ( expression )/
....
/If type-id is void*, a run-time check is made to determine the/
/actual type of expression. The result is a pointer to the complete/
/object pointed to by expression./

So dynamic_cast to "void*" is a distinct language feature.

The point is, that the _value_ of that "void*" will be
comparable wherever the original pointer was cast' from. Which IMHO
can be a handy feature.
 
S

Swampmonster

Ideally, if I could come up with
template <typename T>
bool is_polymorphic(T t) {
...
}

I would be filled with joy :)

Any taker?

::boost::is_polymorphic<T>::value

Look here: http://www.boost.org/libs/type_traits/index.html

The only problem is that the implementation of
::boost::is_polymorphic is basically a hack that relies on
the compiler inserting a vtable-pointer into a polymorphic class,
(and thereby adding to it's size).
Appearently it works with most compilers, but it's way outside
the C++ standard, and there's no guarantee that it will work
as expected under any circumstances or with new versions/revisions
of any compiler you may use today.

But since most boost developers tend to be nifty & smart guys I
think it might be the best way to do it. Which does not mean I'd
use it, but I think chances of finding some better solution are
rather slim.

Of course there might be a better runtime solution - since
::boost::is_polymorphic<T>::value is a compile-time solution. But
then again, what would you do if you have that information at runtime?
If it's a runtime solution you have to have that dynamic_cast
from T to void* somewhere in your program ... even if it would never
be called if T is not polymorphic it's still there and it won't
compile :-(

Or did I miss something?

BTW: dynamic_cast<void*>() will yield the address of the _complete_
object which could be considered the exact opposite of the "most base
type" thing you mentioned.
And: "POD" is not the opposite of "polymorphic" since there are plenty
types that aren't "POD" but aren't "polymorphic" either. E.g.:

struct X { X(); int x; };

is _not_ a POD since it defines a constructor.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top