C ++类/结构数据成员偏移为常量表达式

时间:2011-02-04 15:05:05

标签: c++ alignment packing typetraits compile-time-constant

获取数据成员的偏移量就像这样容易:

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

我想使它成为一个常量的编译时表达式(或使用类型特征)。例如,要使用它来使用成员偏移量来实现基于SFINAE的解决方案,请使用静态断言等。

更新:问题是 - 如何使其成为编译时表达式。不是它是否适用于POD类型,或者C库中是否有标准宏等。

3 个答案:

答案 0 :(得分:3)

虽然我无法得到你的编译器, 以下代码可以由VC8,ideone(gcc-4.3.4)和Comeau编译 在线:

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

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

Gcc的扩展名为__offsetof__。 VC似乎有能力为模板采用非编译时常量 奇怪的说法。 至于Comeau,我不知道Comeau的内部offsetof 不幸的是

顺便提一下,虽然这不会直接回答您的问题,但对于SFINAE 目的,因为成员指针常量可以用作模板参数 你可以专注于它,你可以写如下:

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;
}

希望这有帮助。

答案 1 :(得分:1)

C标准库已经有offsetof来执行此尝试(但您可以在没有UB的情况下使用它)。不幸的是,将它应用于非POD类型仍然会给出不确定的行为,因此对于很多C ++来说它仍然没用。

答案 2 :(得分:0)

首先,将分号放在宏中是一个坏主意 - 它不能用于大表达式。

其次,当有专门为指针设计的完美的类型(即st_int中提供的size_t和ssize_t)时,使用unsigned long是一个坏主意。这些类型在使用32位和64位架构时特别有用 - 而GCC对printf的扩展名为“%zu”,以使用正确的字大小。

G ++在编译时计算它,至少使用-O2和-O3与POD类型