如何在编译时计算班级成员的偏移
How to calculate offset of a class member at compile time?
在C
中给定一个类定义class A
{
public:
//methods definition
....
private:
int i;
char *str;
....
}
是否可以使用C 模板元编程在编译时间计算类成员的偏移?该类不是POD,可以具有原始和对象数据成员的虚拟方法。
基于matthieu M.的答案,但没有宏:
template<typename T, typename U> constexpr size_t offsetOf(U T::*member)
{
return (char*)&((T*)nullptr->*member) - (char*)nullptr;
}
这样称为:
struct X { int a, b, c, d; }
std::cout << "offset of c in X == " << offsetOf(&X::c);
编辑:
Jason Rice是正确的。这不会在C 11中产生实际的恒定表达。考虑到http://en.cppreference.com/w/cpp/language/constant_expression中的限制,看上去不可能 - 尤其没有指针差异,并且reinterpret_cast
可以处于常数表达式中。
好...在C 11中,您实际上可以使用常规的C 设施来计算此类偏移(即,不授权到特定的编译器固有)。
在LiveWorkspace的动作中:
template <typename T, typename U>
constexpr int func(T const& t, U T::* a) {
return (char const*)&t - (char const*)&(t.*a);
}
但是,这依赖于t
是对constexpr
实例的引用,该实例可能不适用于所有类。但是,只要它是constexpr
构造函数,它都不禁止T
具有virtual
方法,甚至禁止使用构造函数。
仍然,这是一个障碍。在未评估的上下文中,我们实际上可以使用std::declval<T>()
模拟具有对象。虽然没有。因此,这对对象的构造函数没有任何特定要求。另一方面,我们可以从这种上下文中提取的价值很少...并且它们确实与当前的编译器构成了问题...好吧,让我们假装它!
在LiveWorkspace的动作中:
template <typename T, typename U>
constexpr size_t offsetof_impl(T const* t, U T::* a) {
return (char const*)t - (char const*)&(t->*a) >= 0 ?
(char const*)t - (char const*)&(t->*a) :
(char const*)&(t->*a) - (char const*)t;
}
#define offsetof(Type_, Attr_)
offsetof_impl((Type_ const*)nullptr, &Type_::Attr_)
我唯一的问题是virtual
继承,因为它的运行时放置基本对象。如果有。
no,通常不是。
存在用于POD(普通旧数据)结构的宏观偏移,并且可以用C 0x稍微扩展到标准布局结构(或其他类似的轻微扩展)。因此,对于那些受限案件,您有一个解决方案。
C 提供了很多编译器作家的自由。我不知道有任何条款可以阻止某些类对班级成员的变量偏移 - 但是,我不确定为什么编译器会这样做。;)
现在,一种使您的代码标准符合代码标准但仍然存在偏移的方法是将您的数据粘贴到POD(或某些C 0x扩展程序)子结构中,然后在哪个oftsit上进行工作,然后进行工作。该子结构而不是整个课程。或者您可以交出标准的合规性。尚不清楚在类中的结构的偏移,但结构内会员的偏移是。
要问的一个重要问题是"我为什么要这个,我真的有一个充分的理由"?
在1996年的书中" C 对象模型内部",由Stanley B. Lippman(原始C 设计师之一)撰写,提到了第4.4章的指针到成员的功能
从获取非静态数据成员的地址返回的值是该成员在类布局中的位置的字节值(加1)。人们可以将其视为不完整的价值。在访问成员的实际实例之前,它需要绑定到类对象的地址。
我隐约记得 1从前世的某个地方中的某个地方,但我以前从未见过或使用过这种语法。
class t
{
public:
int i;
int j;
};
int (t::*pmf)() = &t::i;
至少根据描述,这似乎是"几乎"获得"几乎"的一种很酷的方法。偏移。
,但至少在GCC中似乎不再起作用。我有一个错误:
不能用类型的rvalue int int t :: *'
初始化类型'int(t :: *)的变量
有人在这里发生了任何历史吗?这样的事情仍然可以吗?
网络的问题 - 过时的书永远不会死...
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 编译器在构造函数中计算的成员偏移量不正确
- 如何为类中可能无法计算的成员设置值
- 强制在编译时计算类的类的常量成员
- 计算不相交集合中的成员数
- 如何在编译时计算班级成员的偏移
- 使用在组合类中计算的数据构造成员类
- C++转换:具有指向对象成员的指针,计算指向对象的指针
- 根据对象的成员子对象之一的地址计算对象的地址
- 构造函数中成员启动列表的计算顺序
- 如何使用工会成员的大小计算编译时值
- 在一个函数中使用类的每个成员来计算平均值
- 将数组成员与嵌套循环进行比较,计算满足条件(if)的次数
- 什么等效于C/C++中的java静态最终成员变量,以及如何通过一些计算对其进行初始化
- 是否可以手动计算类成员的字节偏移量
- 帮助成员函数计算距离