Решение:
#include <cstddef>
#include <cstdint>
#include <iostream>
template< class Member, class Parent, size_t memberId = 0>
struct ParentAccess
{
const static ptrdiff_t offset;
Parent & parent() { return *reinterpret_cast<Parent*>(reinterpret_cast<char*>(static_cast<Member*>(this)) -
offset ); }
};
template<class Parent, size_t memberId = 0>
struct A : ParentAccess<A<Parent, memberId>, Parent, memberId>
{
void notifyParent() { this->parent().notify(); }
};
struct Host
{
enum MemberId { A0, A1 };
uint64_t counter = 123;
A<Host/*,A0*/> a;
A<Host,A1> a1;
void notify() { counter++; std::cout << "counter is " << counter << std::endl; }
};
// define the offsets
template<>
const ptrdiff_t ParentAccess<A<Host>,Host>::offset = offsetof(Host, a);
//template<>
//const ptrdiff_t ParentAccess<A<Host,Host::A1>,Host,Host::A1>::offset = offsetof(Host, a1);
// or using a macro to define the offset
#define DEFINE_PARENT_ACCESS_OFFSET(parentClassName, memberClass, memberName, memberId) \
template<>\
const ptrdiff_t ParentAccess<memberClass<parentClassName,parentClassName::memberId>,parentClassName,parentClassName::memberId>::offset = offsetof(parentClassName, memberName)
DEFINE_PARENT_ACCESS_OFFSET(Host,A,a1,A1);
int main()
{
Host h;
h.a.notifyParent();
h.a1.notifyParent();
return 0;
}
https://ideone.com/JeZ2lh
Назовем это «Элемент с нулевыми накладными расходами на шаблон указателя экземпляра класса».