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

发布于 2024-10-16 01:34:32 字数 317 浏览 5 评论 0原文

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

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

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

温折酒 2024-10-23 01:34:32

虽然我不知道你的编译器是什么,
以下代码可以通过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;
}

希望这会有所帮助。

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.

半夏半凉 2024-10-23 01:34:32

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

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.

一笑百媚生 2024-10-23 01:34:32

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

其次,当存在专门为指针设计的完美类型(即 stdint.h 中提供的 size_t 和 ssize_t)时,使用 unsigned long 是一个坏主意。当使用 32 位和 64 位体系结构时,这些类型特别有用——并且 GCC 有 printf 的扩展“%zu”,以使用正确的字大小。

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文