C++ class/structure data member offset as constant expression
-
28-10-2019 - |
Question
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.
Solution
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.
OTHER TIPS
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.
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