is_polymorphic

S

sks

Hello.

I saw this on the message boards but I don't see any explanation on how/why
this works. Doesn't typeid operator only take 1 argument?


template<class T> bool is_polymorphic( const T&r )
{
bool result = false;
typeid(result = true, r);
return result;
}


Thanks.
 
V

Victor Bazarov

sks said:
I saw this on the message boards but I don't see any explanation on
how/why this works. Doesn't typeid operator only take 1 argument?


template<class T> bool is_polymorphic( const T&r )
{
bool result = false;
typeid(result = true, r);
return result;
}

Yes, typeid has only one operand. Are you forgetting the comma
operator?

V
 
S

sks

Victor Bazarov said:
Yes, typeid has only one operand. Are you forgetting the comma
operator?

V

So there is a comma operator that is overloaded for type T or is there some
default/global comma operator? What exactly is the functionality of a comma
operator?
 
A

Alf P. Steinbach

* (e-mail address removed):
I saw this on the message boards but I don't see any explanation on how/why
this works. Doesn't typeid operator only take 1 argument?


template<class T> bool is_polymorphic( const T&r )
{
bool result = false;
typeid(result = true, r);
return result;
}

First, syntax: typeid is an operator, not a function. So the
parenthesis isn't the parenthesis of a function call's argument list.
It's simply a parenthesis, around a comma expression, which is the
single argument to typeid.

The comma operator, when executed, evaluates each argument in sequence
and the result of the expression is the result of the last argument.

Now, semantics. When the expression that is the single argument to
typeid has non-polymorphic static type it isn't evaluated. So in that
case the 'result = true' part isn't executed. But when the expression
is of polymorphic type it is evaluated.

For default-constructible classes an in-practice way of doing this
determination at compile time is

template<class T>
class IsPolymorphic
{
private:
class Derived: T { virtual ~Derived() {} };
public:
enum{ yes = (sizeof(Derived)==sizeof(T)), no = !yes };
};

but this is not guaranteed to work on all compilers, it's only
in-practice, since it relies on (1) having a vtable pointer added when
there are virtual functions, and (2) no size overhead for deriving a
class with no data members, neither of which is guaranteed.

I've never needed either construction, but perhaps determining whether a
class is polymorphic or not, can be useful for something...

Do you recall what it was used for?

Hth.,

- Alf
 
G

Gianni Mariani

sks wrote:
....
So there is a comma operator that is overloaded for type T or is there some
default/global comma operator? What exactly is the functionality of a comma
operator?

In this case it's using the usual "," operator.

expr : expr , expr

The expressions are evaluated left to right and the result and type of
the expression is the value of the last expression.

It's most commonly used in for loops - like this.

for ( i=1, j=2; i < j; ++ i )
 
N

Neelesh Bodas

Alf said:
I've never needed either construction, but perhaps determining whether a
class is polymorphic or not, can be useful for something...

Do you recall what it was used for?

I can think of only point - dynamic_cast is possible only for a
polymorphic type.
(But doing a dynamic_cast on a non-polymorphic type anyways flags an
error at compile time, so that should not be a major usage)

Also, it can be possible to decide whether it is "legal" to derive from
a class or not, without actually looking at the entire interface of the
base class.
(However, this also doesnot sound a very good usage)

I believe there is something more to it. Could you please explain Alf?
 
A

Alf P. Steinbach

* Neelesh Bodas:
I can think of only point - dynamic_cast is possible only for a
polymorphic type.
(But doing a dynamic_cast on a non-polymorphic type anyways flags an
error at compile time, so that should not be a major usage)

Also, it can be possible to decide whether it is "legal" to derive from
a class or not, without actually looking at the entire interface of the
base class.
(However, this also doesnot sound a very good usage)

I believe there is something more to it. Could you please explain Alf?

I'm as baffled as you. It's possible that one could refuse to serialize
to binary form a polymorphic object*. But that would anyway be an
in-practice thing, because non-polymorphic is not the same as POD.



*) I got that idea from checking references to this in the Boost
library, which btw. has a non-restricted in-practice compile time
is_polymorphic, same idea as the one I showed but simply not
implementing the constructor, just declaring it.
 
C

Chris Theis

Neelesh Bodas said:
I can think of only point - dynamic_cast is possible only for a
polymorphic type.
(But doing a dynamic_cast on a non-polymorphic type anyways flags an
error at compile time, so that should not be a major usage)

Also, it can be possible to decide whether it is "legal" to derive from
a class or not, without actually looking at the entire interface of the
base class.
(However, this also doesnot sound a very good usage)

That's certainly an interesting idea, but IMHO it might be good practice to
think about this problem at "implementation-time" and not at runtime using a
function query ;-)

Cheers
Chris
 
C

Chris Theis

[SNIP]
*) I got that idea from checking references to this in the Boost
library, which btw. has a non-restricted in-practice compile time
is_polymorphic, same idea as the one I showed but simply not
implementing the constructor, just declaring it.

Could you please elaborate why/how this works with the declared but not
implemented ctor, because I'm a little lost at the moment.

Cheers
Chris
 
A

Alf P. Steinbach

* Chris Theis:
[SNIP]
*) I got that idea from checking references to this in the Boost
library, which btw. has a non-restricted in-practice compile time
is_polymorphic, same idea as the one I showed but simply not
implementing the constructor, just declaring it.

Could you please elaborate why/how this works with the declared but not
implemented ctor, because I'm a little lost at the moment.

Consider:

#include <iostream>
#include <ostream>

struct NotDefaultConstructible
{
NotDefaultConstructible( double ) {}
};

struct Derived: NotDefaultConstructible
{
Derived();
virtual ~Derived() {}
};

int main()
{
std::cout << sizeof( Derived ) << std::endl;
}

If you comment out the Derived default constructor declaration then the
compiler must generate a default constructor, which it can't do.

Derived can not be instantiated but that doesn't matter.
 

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
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top