This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]