从对象及其成员的地址获取指向成员的指针

Obtaining a pointer-to-member from addresses of an object and its member

我想反转 .* 运算符。

当我有一个指针时,我可以使用 * 取消引用它,然后通过 & 运算符从取消引用的值返回到指针。

有了指向成员的指针,我可以使用 .* 运算符(提供对象实例)取消引用它,但是没有运算符可以从对象及其取消引用的字段中获取原始的指向成员的指针。

考虑以下数据结构:

struct Point { double x, y, z; };

现在我需要从 (Point&, double&) 对中获取指向成员 double Point::* 的指针,其中 double &Point& 对象的一个​​字段。

换句话说,我需要一个函数 to_member_ptr 这样:

template<typename DataType, typename Member>
constexpr Member DataType::* obtain_member_ptr(const DataType &that, const Member &fieldInThat);

int main(int, char*[]) {
    Point pt;
    static_assert(obtain_member_ptr(pt, pt.x) == &Point::x, "error");
    static_assert(obtain_member_ptr(pt, pt.y) == &Point::y, "error");
    static_assert(obtain_member_ptr(pt, pt.z) == &Point::z, "error");
}

我可以为给定的数据类型手写如下:

constexpr double Point::* obtain_member_ptr(const Point &that, const double &fieldInThat)     {
    if(&that.x == &fieldInThat) return &Point::x;
    if(&that.y == &fieldInThat) return &Point::y;
    if(&that.z == &fieldInThat) return &Point::z;
    return nullptr;
}

但这似乎是一个普通的样板文件,我觉得应该有一种方法可以让编译器为我做这件事。

如何从对象及其字段中可移植地获取指向对象的指针?

使用visit_struct,您可以先添加反射:

struct Point { double x, y, z; };

VISITABLE_STRUCT(Point, x, y, z);

然后访问你的结构:

template <typename C, typename T>
struct MemberPtrGetter
{
    constexpr MemberPtrGetter(const C& c, const T& field) : c(c), field(field) {}

    // Correct type, check reference.
    constexpr void operator() (const char* name, T C::*member) const
    {
        if (&(c.*member) == &field)
        {
            res = member;
        }
    }

    // other field type -> ignore
    template <typename U> constexpr void operator() (const char* , U C::*member) const {}

    const C& c;
    const Member& field;
    Member C::* res = nullptr;
};


template<typename C, typename T>
constexpr T C::* obtain_member_ptr(const C& c, const T& field)
{
    MemberPtrGetter<C, T> visitor{c, field};
    visit_struct::apply_visitor<C>(visitor);
    return visitor.res;
}