2

获取数据成员的偏移量就像这样简单:

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

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

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

4

3 回答 3

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 似乎有能力为模板参数采用非编译时常量。至于科莫,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;
}

希望这可以帮助。

于 2011-02-04T18:52:29.317 回答
1

C 标准库已经offsetof可以做到这一点(但您可以在没有 UB 的情况下使用它)。不幸的是,将它应用于非 POD 类型仍然会产生未定义的行为,因此对于很多 C++ 来说它仍然没用。

于 2011-02-04T15:09:37.967 回答
0

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

unsigned long其次,当有专门为指针设计的非常好的类型(即 size_t 和 ssize_t,在 stdint.h 中提供)时使用它是一个坏主意。这些类型在使用 32 位和 64 位架构时特别有用——而且 GCC 对 printf 有一个扩展,“%zu”,以使用正确的字长。

G++ 在编译时计算这个,至少使用 -O2 和 -O3 以及 POD 类型

于 2011-02-04T19:08:23.267 回答