Инвертировать указатель на член (т.е. получить адрес содержащей структуры)
У меня есть структура (Member), которую можно использовать только в качестве члена данных в какой-либо другой структуре (Container). По соглашению имя члена всегда m. Есть ли надежный способ для члена получить адрес содержащей структуры?
template<typename Struct>
struct Member;
{
const Struct& s = ??;
// this - &Struct::m
};
struct Container
{
Member<Container> m;
};
Я надеялся, что, возможно, используя указатель на член &Container::m
может помочь вычислить обратно по адресу самого объекта Member?
2 ответа
Нет, ты не можешь сделать это. Вы можете определить смещение m
в Container
и сделать указатель арифметики, чтобы угадать результирующий адрес Container
, но это будет:
- ненадежный
- склонны к катастрофическим ошибкам
- UB (и, следовательно, может вызвать симптомы, включая путешествие во времени - нет, серьезно!)
Это может работать согласованно на нескольких платформах, если у вас отключены все оптимизации, но на самом деле, пожалуйста, просто не делайте.
Либо передать указатель / ссылку на Container
в Member<Container>
конструктор (после добавления одного), или еще раз переосмыслить свой дизайн. Почему член должен знать об объекте, инкапсулирующем его? Это почти всегда неправильно (хотя есть несколько проходимых вариантов использования).
Не уверен насчет "надежного", и этот тип хака не должен поощряться, но следующее должно дать вам хорошую отправную точку:
#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 было реальное ненулевое смещение для тестирования, но оно также работает и для нулевого смещения.