我希望反转.*
运算符。
当我有一个指针时,我可以用*
取消引用它,然后从取消引用的值返回到指针&
运算符。
使用指向成员的指针,我可以使用运算符(提供对象实例(取消引用它.*
但没有运算符可以从对象及其取消引用的字段中获取原始指向成员的指针。
请考虑以下数据结构:
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;
}