【发布时间】:2020-05-05 18:42:47
【问题描述】:
我有一个struct 和其他一些structs 作为成员。外部和内部结构都是StandardLayout(甚至可以假设内部是普通的旧数据)。像这样的:
struct Inner1 {
int a = 0, b = 0;
};
struct Inner2 {
int c = 0, d = 0;
};
struct Outer {
Inner1 x;
std::string s;
Inner2 y;
};
我想编写一些函数,它采用 Outer& 和某种类型的对象 T,可以返回任何嵌套字段的值,具体取决于参数:
int get(Outer& o, T field);
如果Outer 是一个平面结构,指向成员的指针正是我所需要的,但它不是平面结构。
简单的方法是将所有字段的T 设为enum 并写一个switch,但我认为它效率不高。更快的方法是使T 偏移并写入
int get(Outer& o, size_t field) {
return *reinterpret_cast<int*>(reinterpret_cast<char*>(o) + field);
}
然后将其称为get(o, offsetof(Outer, y) + offsetof(Inner2, c))。它可以工作,但我不确定它是否可以保证工作 - 像这样对偏移量求和是否正确,以及通过偏移量获取成员值是否安全。
那么问题来了:这种方式安全吗?如果没有,有没有安全的方法?构造T 的值可以是任意复杂的,但是使用它们应该很快。
动机:我需要将一些嵌套字段中的值按某种顺序放置,在启动时已知,但在编译时不知道。我想在启动时创建一个 T 数组,然后在获取特定对象时,使用这个预先计算的数组。
[UPD]:所以会这样使用:
void bar(int);
void foo(Outer& o, vector<T>& fields) {
for (auto& field : fields) {
bar(get(o, field));
}
}
【问题讨论】:
-
我没有看到使用偏移量的优势。它要求调用者知道该偏移量,因此您也可以将指向成员的指针作为参数,以避免与
reinterpret_casts -
谢谢,但我认为它们不适用于嵌套成员。
-
使用
offsetof应该没问题。这是唯一编译器支持的获取包含成员地址的方法,因为没有关于将包含的位置和内容的标准。但是offsetof是一个 C 函数。为什么你认为enum和switch很慢而且有点令人困惑。很难看到这种情况还不够。 -
可能有几百个字段,而
switch是线性时间运行的,所以会很慢。 -
@mihaild 我希望开关优化为查找表,因此它可能是恒定时间。
标签: c++ pointer-to-member offsetof