2015-02-26 4 views
0

У меня есть struct (Member), который может использоваться только как элемент данных в какой-либо другой структуре (Контейнер). По соглашению имя члена всегда m. Есть ли надежный способ для члена получить адрес содержащейся структуры?Инвертировать указатель на элемент (т. Е. Получить адрес содержащейся структуры)

template<typename Struct> 
struct Member; 
{ 
    const Struct& s = ??; 
        // this - &Struct::m 
}; 

struct Container 
{ 
    Member<Container> m; 
}; 

Я надеялся, что, возможно, используя указатель на член &Container::m может помочь вычислить назад от адреса самого объекта-членов?

+1

Это не имеет никакого смысла. '& Container :: m' - это * смещение *' '' '' Container'. Он не указывает на какой-либо конкретный объект 'Member'. – Angew

+3

Если содержащийся класс является стандартным макетом, вы должны иметь возможность работать с 'offsetof'. – Angew

+0

Правильные строчки '& Struct :: m'. Проблема заключается в этом. Где будет инициализироваться и на что ссылается? – chmike

ответ

5

Нет, вы не можете этого сделать. Вы можете определить смещение m в Container и делать арифметические операции над указателями, чтобы угадать в результате адрес Container, но это будет:

  • ненадежные
  • склонны к катастрофическим ошибкам
  • UB (и, следовательно, может симптомы вызывают включая путешествие во время — no, seriously!)

Это могущество последовательно работать на несколько platfo rms, если у вас все оптимизации отключены, но, действительно, пожалуйста, просто не делайте этого.

Либо передать указатель/ссылку на Container в конструктор Member<Container> (после добавления его), либо еще раз переосмыслить свой дизайн. Почему член должен знать об инкапсулирующем его объекте? Это почти всегда неверно (хотя есть и некоторые приемлемые варианты использования).

+0

Передача ссылки на Container в член - это то, что я сейчас (планирую) делать. Я думаю о том, как избежать вариационной формы CRTP, превращая функции в базовые классы CRTP в вызываемые элементы данных. – Rumburak

0

Не уверен, что «надежный», и это своего рода хак, что не следует поощрять, но следующее должно дать вам хорошую отправную точку:

#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; 
} 

Я добавил некоторые элементы, так что м есть фактическое ненулевое смещение для тестирования, но оно также работает для нулевого смещения.

+0

О боже нет, просто нет –

+0

@ Светлость: да, я знаю. –

+0

Вы можете вычислить 'offset' с' offsetof'. – Jarod42