反转指向成员的指针(即获取包含结构的地址)
Invert pointer to member (i.e. get the address of the containing struct)
我有一个结构(成员)只能在其他结构(容器)中用作数据成员。按照惯例,成员的名字总是 m。成员获取包含结构的地址是否有可靠的方法?
template<typename Struct>
struct Member;
{
const Struct& s = ??;
// this - &Struct::m
};
struct Container
{
Member<Container> m;
};
我希望使用指向成员的指针 &Container::m
可能有助于从成员对象本身的地址计算回来?
不确定 "reliable",这种 hack 不应该被鼓励,但以下内容应该是一个很好的起点:
#include <cassert>
#include <cstddef>
#include <type_traits>
template<typename Struct>
struct Member
{
Struct const* s = (Struct*)&((char*)this)[-(int)offsetof(Struct, m)];
};
struct Container
{
int abc;
int def;
Member<Container> m;
};
int main(int argc, char* argv[])
{
assert(std::is_standard_layout<Container>::value);
Container c;
Container const *p1 = &c;
Container const *p2 = c.m.s;
bool test = p1 == p2;
return 0;
}
我添加了一些成员,使 m 具有用于测试的实际非零偏移量,但它也适用于零偏移量。
不,你不能这样做。您可以确定 Container
中 m
的偏移量,并进行指针运算来猜测 Container
的结果地址,但这将是:
- 不可靠
- 容易出现灾难性错误
- UB(因此会导致时间旅行等症状 — no, seriously!)
如果您禁用了所有优化,它可能在一些平台上始终如一地工作,但是,真的,请不要这样做。
要么将 pointer/reference 传递给 Container
到 Member<Container>
的构造函数(添加一个之后),要么进一步重新考虑您的设计。为什么成员需要知道封装它的对象?这几乎总是错误的(尽管有一些可以通过的用例)。
我有一个结构(成员)只能在其他结构(容器)中用作数据成员。按照惯例,成员的名字总是 m。成员获取包含结构的地址是否有可靠的方法?
template<typename Struct>
struct Member;
{
const Struct& s = ??;
// this - &Struct::m
};
struct Container
{
Member<Container> m;
};
我希望使用指向成员的指针 &Container::m
可能有助于从成员对象本身的地址计算回来?
不确定 "reliable",这种 hack 不应该被鼓励,但以下内容应该是一个很好的起点:
#include <cassert>
#include <cstddef>
#include <type_traits>
template<typename Struct>
struct Member
{
Struct const* s = (Struct*)&((char*)this)[-(int)offsetof(Struct, m)];
};
struct Container
{
int abc;
int def;
Member<Container> m;
};
int main(int argc, char* argv[])
{
assert(std::is_standard_layout<Container>::value);
Container c;
Container const *p1 = &c;
Container const *p2 = c.m.s;
bool test = p1 == p2;
return 0;
}
我添加了一些成员,使 m 具有用于测试的实际非零偏移量,但它也适用于零偏移量。
不,你不能这样做。您可以确定 Container
中 m
的偏移量,并进行指针运算来猜测 Container
的结果地址,但这将是:
- 不可靠
- 容易出现灾难性错误
- UB(因此会导致时间旅行等症状 — no, seriously!)
如果您禁用了所有优化,它可能在一些平台上始终如一地工作,但是,真的,请不要这样做。
要么将 pointer/reference 传递给 Container
到 Member<Container>
的构造函数(添加一个之后),要么进一步重新考虑您的设计。为什么成员需要知道封装它的对象?这几乎总是错误的(尽管有一些可以通过的用例)。