C++ class/structure data member offset as constant expression

1.9k views Asked by At

Taking offset of a data member is as easy as this:

#define MEMBER_OFFSET(Type, Member) \
    ((unsigned long)(((char *)&((Type *)0)->Member) - (char *)0));

I want to make this a constant compile-time expression (or use type traits). For example, to use it to implement SFINAE based solutions using member offsets, use it static assertions etc.

UPDATE: The question is - how to make it a compile-time expression. Not whether it works with POD types, or is there a standard macro in C library etc.

3

There are 3 answers

5
Ise Wisteria On BEST ANSWER

Though I can't get what your compiler is, the following code can be compiled by VC8, ideone(gcc-4.3.4), and Comeau online:

struct A { int i; };
template< size_t > struct S;

int main() {
  S< offsetof( A, i ) > *p;
}

Gcc has __offsetof__ extension. VC seems to have a capability to take a non-compile-time constant for a template argument strangely. As for Comeau, I have no idea about the internal of Comeau's offsetof unfortunately.

Incidentally, though this won't answer your question directly, as for SFINAE purpose, since a member pointer constant can be used as a template argument and you can specialize on it, you can write as the following:

struct A {
  int i, j;
};

template< int A::* > struct S;
template<> struct S< &A::i > { static char const value = 'i'; };
template<> struct S< &A::j > { static char const value = 'j'; };

int main() {
  cout<< S< &A::i >::value <<endl;
  cout<< S< &A::j >::value <<endl;
}

Hope this helps.

2
Foo Bah On

First, its a bad idea to put the semicolon in the macro -- it cant be used in a large expression.

Second, its a bad idea to use unsigned long when there are perfectly good types specifically designed for pointers (namely size_t and ssize_t, provided in stdint.h). These types are especially useful when using 32 and 64 bit architectures -- and GCC has an extension to printf, "%zu", to use the correct word size.

G++ computes this at compile-time, at least with -O2 and -O3 with POD types

6
Jerry Coffin On

The C standard library already has offsetof that does what this attempts to (but you can use it without UB). Unfortunately, applying it to a non-POD type still gives undefined behavior, so for a lot of C++ it's still useless.