从指针到成员恢复父级

bcr*_*bcr 7 c++ parent pointer-to-member

假设我们有一个指向类的字段指向类的成员.我们还有一个指向该类的特定实例中的特定字段的指针.例如,我们可能会有这样的事情:

class A {
     B inner_object;
}

A* myA = /* ... */
B* ptr = &myA->inner_object;
B A::* memPtr = &A::inner_object;
Run Code Online (Sandbox Code Playgroud)

有没有办法使用ptrmemPtr恢复myA?也就是说,如果我们没有已经有了一个明确的指针myA,我们可以做一个出来的ptrmemPtr

bcr*_*bcr 6

经过大量研究后...

这实际上是在大多数工业侵入列表实现中完成的。然而,它确实需要一些技巧。

Boost 侵入式结构使用以下内容(是的,它是特定于实现的)

template<class Parent, class Member>
inline const Parent *parent_from_member(const Member *member, const Member Parent::*   ptr_to_member)
{
   return (const Parent*)((const char*)member -
      offset_from_pointer_to_member(ptr_to_member));
}


template<class Parent, class Member>
inline std::ptrdiff_t offset_from_pointer_to_member(const Member Parent::* ptr_to_member)
{
   //The implementation of a pointer to member is compiler dependent.
   #if defined(BOOST_INTRUSIVE_MSVC_COMPLIANT_PTR_TO_MEMBER)
   //msvc compliant compilers use their the first 32 bits as offset (even in 64 bit mode)
   return *(const boost::int32_t*)(void*)&ptr_to_member;
   //This works with gcc, msvc, ac++, ibmcpp
   #elif defined(__GNUC__)   || defined(__HP_aCC) || defined(BOOST_INTEL) || \
     defined(__IBMCPP__) || defined(__DECCXX)
   const Parent * const parent = 0;
   const char *const member = reinterpret_cast<const char*>(&(parent->*ptr_to_member));
   return std::ptrdiff_t(member - reinterpret_cast<const char*>(parent));
   #else
   //This is the traditional C-front approach: __MWERKS__, __DMC__, __SUNPRO_CC
   return (*(const std::ptrdiff_t*)(void*)&ptr_to_member) - 1;
   #endif
}
Run Code Online (Sandbox Code Playgroud)

本质上与 Linux 内核中使用 container_of 宏管理侵入列表的做法相同(尽管是在 C 语言中)(但当然不使用 ptr-to-members):

#define container_of(ptr, type, member) ({ \
            const typeof( ((type *)0)->member ) *__mptr = (ptr); 
            (type *)( (char *)__mptr - offsetof(type,member) );})
Run Code Online (Sandbox Code Playgroud)