Я хотел бы составить указатели членов. В основном у меня есть основной класс с другим членом. Как создать указатель на член для основного класса, который будет указывать на член члена этого класса. Я надеюсь, что код ниже объясняет, что я пытаюсь сделать:
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 !
}
Использование подкласса здесь сбивает с толку, так как обычно подкласс используется для наследования, поэтому давайте поговорим о элемент данных: sub_unit
является членом данных Unit
,
И то, что вы просите, не возможно, Unit::*
может представлять только смещение в любом Unit
сам или один из его базовых классов:
struct SubUnit { int value; };
struct Unit: SubUnit {};
int main() { int Unit::* p = &Unit::value; }
Кажется, вы должны сделать это в два этапа:
SubUnit Unit::*pSub = &Unit::sub_unit;
int SubUnit::*pValue = &SubUnit::value;
Unit u;
int theVal = (u.*pSub).*pValue;
Это похоже на дубликат этого вопроса:
Указатель на вложенный элемент данных — не возможно?
Суть принятого ответа гласит:
Указатель на член может быть сформирован только выражением типа &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;
Обходной путь может быть построен с помощью лямбды:
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;
}