views:

271

answers:

7

If I have a derived class with multiple bases, each this pointer for each base will be different from that of the derived object's this pointer, except for one. Given two types in an inheritance hierarchy, I'd like to detect at compile time whether they share the same this pointer. Something like this should work, but doesn't:

BOOST_STATIC_ASSERT(static_cast<Base1*>((Derived *)0xDEADBEEF) == (Derived*)0xDEADBEEF);

Because it needs to be an 'integral constant expression' and only integer casts are allowed in those according to the standard (which is stupid, because they only need compile time information if no virtual inheritance is being used). The same problem occurs trying to pass the results as integer template parameters.

The best I've been able to do is check at startup, but I need the information during compile (to get some deep template hackery to work).

A: 

You can't detect at compile time if they share the same this pointer. They haven't been created yet. How can the compiler possibly know?

Goz
By that logic offsetof() would not work either.
MSalters
offsetof() has nothing to do with a this pointer. Its purely an offset of a member from the start of a class.
Goz
My point precisely. He's looking purely for the offset of a base class from the start of a derived class.
MSalters
+1  A: 

I don't know how to check what you wan't but note that your assumption is false in presence of empty base classes. Any number of them can share the same offset from the start of the object, as long as they are of different type.

AProgrammer
Thinking a little more about your problem -- and assuming that your question is about the offset of base classes and not about pointers -- I'd have though that offsetof returns a constant integral expression and so should be able to do the check if your can constraint yourself to POD. But g++ complains if I use offsetof with a derived class and I wonder what I'm missing.
AProgrammer
@AProgrammer: is the thing that you're missing, that any derived class is by definition non-POD? OP therefore cannot use only POD classes.
Steve Jessop
Oops, I looked too often at the current draft (where standard-layout which is the precondition to the use of offsetof can have non virtual base classes).
AProgrammer
+1  A: 

I am not even sure that this offset is a constant in the first place. Do you have normative wording suggesting otherwise?

I'd agree that a non-const offset would be bloody hard to implement in the absence of virtual inheritance, and pointless to boot. That's besides the point.

MSalters
+2  A: 

Classes do not have a this pointer - instances of classes do, and it will be different for each instance, no matter how they are derived.

anon
He's creating a fake object pointer however, and attempting to use the base-class offset assumptions that are made at compile time to infer whether it has the base class or not. He doesn't need a real object - I think it's far too implementation dependent however.
polyglot
+1  A: 

What about using

BOOST_STATIC_ASSERT(boost::is_convertible<Derived*,Base*>::value)

as documented in the following locations...

http://www.boost.org/doc/libs/1_39_0/doc/html/boost_staticassert.html

http://www.boost.org/doc/libs/1_38_0/libs/type_traits/doc/html/boost_typetraits/reference/is_convertible.html

polyglot
Even if that's not perfect, looking at their implementation may assist you :)
polyglot
Unfortunately I need the actual offset. Their implementation may still assist me... once I understand it ;) It's pretty dense.
Joseph Garvin
A: 

I didn't realize that the compiler would insert this check at runtime, but your underlying assumption isn't entirely correct. Probably not in ways that you care about though: the compiler can use the Empty Base Class Optimization if you happen to inherit from more than one base class with sizeof(base class)==0. That would result in (base class *)(derived *)1==at least one other base class.

Like I said, this probably isn't something you would really need to care about.

MSN
+1  A: 

I am trying to solve this exact same issue. I have an implementation that works if you know what member variable is at the beginning of the base class's layout. E.g. if member variable "x" exists at the start of each class, then the following code will work to yield the byte offset of a particular base class layout from the derived class layout: offsetof(derived, base2::x).

In the case of:
struct base1 { char x[16]; };
struct base2 { int x; };
struct derived : public base1, public base2 { int x; };
static const int my_constant = offsetof(derived, base2::x);

The compiler will properly assign "16" to my_constant on my architecture (x86_64).

The difficulty is to get "16" when you don't know what member variable is at the start of a base class's layout.