This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: invalid offsetof from non-POD type
On Sat, 26 Apr 2003 11:44:59 +0100 Nathan Sidwell
<nathan at codesourcery dot com> wrote:
> Matthias Benkmann wrote:
>
> > Can't you wrap the POD-stuff in a real POD like this:
> yes, but then you (well I've had to in the past), do something like
>
> class Foo {
> public:
> struct Pod { ...};
> ...
> };
>
> class BiggerFoo : public Foo {
> public
> struct Pod : Foo::Pod { ... }; // this is a lie now
> ...
> };
>
> It gets annoying to have to write
> struct Pod { struct Foo::Pod base; ... };
> as that exposes the hierachy to all BiggerFoo::Pod users.
Doesn't inheritance always yield a non-POD? So this wouldn't even work
with offsetof, would it?
In any case I wouldn't use offsetof in the 1st place for exposing certain
fields to a scripting language. I'd prefer a solution such as this:
#include <cstddef>
#include <iostream>
using namespace std;
class ThingPtr
{
public:
enum Type {Int, Long, Char};
int& toInt() {if (t!=Int) throw 13; else return *((int*)p);};
long& toLong() {if (t!=Long) throw 13; else return *((long*)p);};
char& toChar() {if (t!=Char) throw 13; else return *((char*)p);};
Type t;
void* p;
};
class Foo
{
public:
int x;
char fillerdata[256];
int y;
static void getX(Foo& this_,ThingPtr& target)
{target.t=ThingPtr::Int; target.p=&this_.x;};
static void getY(Foo& this_,ThingPtr& target)
{target.t=ThingPtr::Int; target.p=&this_.y;};
Foo()
{
x = 0;
y = 0;
}
virtual ~Foo(){}; //need at least 1 virtual method for dynamic_cast<>
};
class Bar:public Foo
{
char z;
public:
static void getZ(Foo& this_,ThingPtr& target)
{target.t=ThingPtr::Char; target.p=&dynamic_cast<Bar&>(this_).z;};
};
typedef void (*getField)(Foo&,ThingPtr&);
int main()
{
getField ygetter = &Foo::getY;
getField zgetter = &Bar::getZ;
Foo foo;
// get a reference to y using the computed offset
ThingPtr tp;
(*ygetter)(foo,tp);
int& yref=tp.toInt();
// test it by assigning
yref = 15;
cout << "foo values: " << foo.x << ", " << foo.y << endl;
//test type checking
try{
tp.toLong();
}catch(...)
{
cout<<"Type checking on field type works"<<endl;
}
try{
(*zgetter)(foo,tp);
}catch(...)
{
cout<<"Type checking on object type works"<<endl;
}
return 0;
}
This gives you much more flexibility and type safety. Some macro-magic can
be used to eliminate all the type-checking in the release build including
all the dynamic_casts (although of course you should only do this if the
little bit of extra performance really makes a *measurable* difference,
which is doubtful if an interpreted scripting language is involved).
MSB
--
Want to learn long division in ternary?
Contact me at ICQ 2101001122212.01/0.00002