Могу ли я составить указатели на участника

Я хотел бы составить указатели членов. В основном у меня есть основной класс с другим членом. Как создать указатель на член для основного класса, который будет указывать на член члена этого класса. Я надеюсь, что код ниже объясняет, что я пытаюсь сделать:

  struct SubUnit
{
int   value;
};
struct Unit
{
SubUnit sub_unit;
};

void Test()
{
SubUnit Unit::* ptr1 = &Unit::sub_unit; // WORKING
int Unit::* ptr2 = &Unit::sub_unit::value; // NOT WORKING !
}

6

Решение

Использование подкласса здесь сбивает с толку, так как обычно подкласс используется для наследования, поэтому давайте поговорим о элемент данных: sub_unit является членом данных Unit,

И то, что вы просите, не возможно, Unit::* может представлять только смещение в любом Unit сам или один из его базовых классов:

struct SubUnit { int value; };

struct Unit: SubUnit {};

int main() { int Unit::* p = &Unit::value; }
3

Другие решения

Кажется, вы должны сделать это в два этапа:

SubUnit Unit::*pSub = &Unit::sub_unit;
int SubUnit::*pValue = &SubUnit::value;

Unit u;
int theVal = (u.*pSub).*pValue;
4

Это похоже на дубликат этого вопроса:
Указатель на вложенный элемент данных — не возможно?

Суть принятого ответа гласит:

Указатель на член может быть сформирован только выражением типа &qual_id, который не ваш случай

Стандарт C ++ говорит в пункте 8.3.3:
Указатель на участников:

В декларации T D, где D имеет вид

  nested-name-specifier * attribute-specifier-seqopt cv-qualifier-seqopt D1

и спецификатор вложенного имени обозначает класс, а тип идентификатора в объявлении T D1 равен
«Производный-декларатор-тип-список Т», тогда тип идентификатора D — «производный-декларатор-тип-список»
квалификатор-seq указатель на член класса nested-name-спецификатор типа T ».
Необязательный атрибут-спецификатор-seq (7.6.1) относится к указателю на член.

Оказывается, есть способ сделать то, что вы хотите, который, кажется, работает на моем текущем компиляторе (apple llvm 5.0). Тем не мение, это очень зависит от реализации, и я бы определенно рекомендовал не использовать это решение в любом виде производственного кода:

//added a few data members to make it non-trivial
struct SubUnit {
double d;
int   value;
};
struct Unit {
bool b;
char c;
SubUnit sub_unit;
};

intptr_t suOffset = offsetof(Unit, sub_unit);
intptr_t intOffset = offsetof(SubUnit, value);
intptr_t totalOffset = suOffset + intOffset;

// there is no way to convert this offset directly in a
// pointer-to-member AFAIK, so we have to trick a bit
int Unit::* pui = nullptr;
auto puiAddr = &pui;
intptr_t* puiAddrAsIntPtrPtr = reinterpret_cast<intptr_t*>(puiAddr);
*puiAddrAsIntPtrPtr = totalOffset;

//pui should now "point to the right offset"//let's test it
Unit u;
u.sub_unit.value = 123456;

int val = u .* pui;
std::cout << "val: " << val << std::endl;
2

Обходной путь может быть построен с помощью лямбды:

    struct SubUnit
{
int   value;
};
struct Unit
{
SubUnit sub_unit;
};

void Test()
{
auto  composed_mem_ptr = [](Unit & unit) -> int&{ return  unit.sub_unit.value; };
Unit  unit0{};
composed_mem_ptr(unit0) = 7;
}
0
По вопросам рекламы [email protected]