LINUX.ORG.RU

Указатель на член класса являющий массивом и доступ к его (массива) элементам?

 


0

2

Такой вот изврат. Есть скажем структура

struct A{
   double x[10];
};
Я хочу указатель на член x (и доступ при разименовании к любому элементу), и/или указатель скажем на третий элемент (как указатель на член)
double A::*[10] p = &A::x;
double A::*p = &A::x [3];
че то в этом роде, но оно нефига не собирается (ни то ни то, на уровне синтакиса не так). Я могу конечно в ручную приводить типы и вычислять смещения, но хочется это делать Ъ...

★★★★★

Последнее исправление: AIv (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Шаман! Спасибо;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

И вообще, вот я знаю смещение поля от начала структуры (в байтах, аллах дал). Могу я его кастануть к указателю на член? А то в лоб не дает

	double A::* p2 = (double A::*)16;
...
error: invalid cast from type ‘int’ to type ‘double A::*’

AIv ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

Тогда, наверное, (*(&A::x))[3]

error: invalid use of ‘unary *’ on pointer to member

зачем это нужно. Как там звучит настоящий вопрос?

Так и звучит. У меня есть некая заморочная хитропараметризованная функция, которая принимает через аргумент шаблона указатель на член класса (скажем типа double). Беда в том, что поле на которое передаем указатель может быть не просто полем, но и элементом массива.

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

AIv ★★★★★
() автор топика
Ответ на: комментарий от KennyMinigun

Да, но это ответ тока на первый вопрос (и taigunner на него уже ответил;-)). Я не там скобочку ставил.

AIv ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

До этого я сам додумался, интересно как без объекта (указатель на член, а не просто указатель;-)))).

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Ну я поэтому и спрашивал, как звучит настоящий вопрос. ЕМНИП, указатель на член - это смещение от начала объекта, он не имеет смысла без указателя на объект.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Это понятно. Непонятно почему нельзя смещение (число в байтах) кастануть к указателю на член. Можно конечно и со смещением работать, но это довольно уродливо выглядит, типа

*(T*)((char*)&a+offset)
вместо
a.*p

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Непонятно почему нельзя смещение (число в байтах) кастануть к указателю на член

Потому что оно является смещением от начала только в простых случаях. Когда в дело вступает множественное виртуальное наследование, там уже не смещение, а что-то более сложное. Правда, деталей я не помню.

tailgunner ★★★★★
()
Ответ на: комментарий от AIv

Ну для POD-типов то оно всегда смещение как смещение?

Для ответа нужно быть действующим Си++-прогером :) Я _думаю_, что для POD и любого не-виртуального наследования это просто смещение. Но как преобразовать его именно в указатель на член, я не знаю %)

tailgunner ★★★★★
()
Ответ на: комментарий от AIv

А что собственно мешает использовать чистое смещение, в духе ptrdiff_t, и преобразование типов?

Ты всё равно по ходу без преобразований не выкрутишься, раз не хочешь передавать 2 параметра.

Pavval ★★★★★
()
Ответ на: комментарий от AIv

Да, для POD-типов оно _всегда_ смещение как смещение. В С++ спецификации даже чёткое определение POD-типов и POD-классов выделено.

Система загрузки данных из БД в память в MaNGOS, например, именно на этом факте построена. Куча строк типа «iiiiiiiccllllillllcccccc» и огромный кусок памяти, который из этих строк распарсивается по i -> int, c - char *, l -> long.

Adonai ★★★
()
Последнее исправление: Adonai (всего исправлений: 3)

Есть offsetof, работает для таких типов (это к вопросу получения указателя на член и использования его без указателя на сам объект).

yoghurt ★★★★★
()

Крайне сомнительная идея (вообще UB), но всё-таки:

template <class C, typename M, typename T>
union beware {
    M C::* member;
    T* pointer;
};

#include <cstdint>

struct A {
    uint16_t x, y;
    double z[4];
};

#include <cstdio>

int main() {

    A a = {0x1234, 0x5678, {1., 2., 3., 4.}};

    {
        beware<A, uint16_t, uint8_t> u;
        u.member = &A::x;
        u.pointer += 1;
        printf("%x\n", a.*u.member);
        // 7812
    }

    {
        beware<A, uint8_t[], uint8_t> u;
        u.pointer = reinterpret_cast<uint8_t*>(2);
        printf("%x\n", (a.*u.member)[1]);
        // 56
    }

    {
        beware<A, double[4], double> u;
        u.member = &A::z;
        u.pointer += 1;
        printf("%f\n", (a.*u.member)[1]);
        // 3.000000
    }

}
quasimoto ★★★★
()
Ответ на: комментарий от tailgunner

Для ответа нужно быть действующим Си++-прогером :)

Звучит почти так же гордо, как быть «действующим вулканом»;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от quasimoto

O! Я все время забываю про возможности юниона в качестве грязных хаков с кастингом, спасибо!

#include <stdio.h>

template<typename A, typename T> union FuckOffBiern{
    long offset;
    T A::* ptr;
};
template<typename A, typename T, int D> T A::* get_ptr(T (A::* ptr)[D], int i){
	FuckOffBiern<A,T> pu; pu.ptr = (T A::*)ptr;
	pu.offset += i*sizeof(T);
	return pu.ptr;
}

struct A{
	double x[10];
};

int main(){
      A a; a.x[2] = 123;
      printf("%g\n", a.*get_ptr(&A::x, 2) );
}

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

a.*get_ptr(&A::x, 2)

И чем такая запись лучше?

Действующие вулканы подсказывают, что правильно делать так: double *GetXRef() { return x; }

А ещё правильнее так: std::array<double> &GetXRef() {return x; }

anonymous
()
Ответ на: комментарий от AIv
Ответ на: комментарий от quasimoto

Ваша же идея, но другими словами

Дебажная сборка (без -O2, -O3) будет работать. Остальное — проблемы пользователей.

Как правильно, я написал выше.

anonymous
()
Ответ на: комментарий от AIv

Непонятно почему нельзя смещение (число в байтах) кастануть к указателю на член.

Потому что указатель на член кроме собственно самого смещения относительно начала структуры (класса) содержит еще указатель на сам объект, который передается при вызове функции-члена первым аргументом неявно как this, а при доступе к переменной члену используется как this->member_variable. Само по себе абстрактное смещение без конкретизации объекта бессмыссленно.

m0rph ★★★★★
()
Ответ на: комментарий от AIv

O! Я все время забываю про возможности юниона в качестве грязных хаков с кастингом, спасибо!

Поздравляю, ты только что сделал все необходимые приготовления для стрельбы по собственным яйцам! Работоспособность твоего костыля зависит от конкретного компилятора.

m0rph ★★★★★
()
Ответ на: комментарий от m0rph

похоже, четыре звезды — это диагноз

указатель на член заодно содержит кнопку «выполнить все необходимые вычисления», да

anonymous
()
Ответ на: комментарий от ilovewindows

ловля жуков в релизной сборке, потому что не ловятся в дебажной — традиционное народное развлечение

anonymous
()
Ответ на: комментарий от anonymous

Как-то слишком общо. Это реально с программированием связано ? Имхо эти нетривиальные упражнения с членами класса доставляют не по-детски, только непонятно как, чую жизнь мимо проходит.

ilovewindows ★★★★★
()
Последнее исправление: ilovewindows (всего исправлений: 1)
Ответ на: a.*get_ptr(&A::x, 2) от anonymous

И чем такая запись лучше?

Лучше чем что?

Действующие вулканы подсказывают, что правильно делать так: double *GetXRef() { return x; }

И какое это имеет отношение к указателю на член O_O? По такому коду однозначно детектится ООП головного мозга в терминальной стадии.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

FuckOffBiern

Bjarne.

И, если уж ты пошел по пути грязных хаков, по крайней мере проверь, что A - это POD или standard layout, что там тебе больше подходит

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Поскольку у нас не продакшен какой нить, а поделки для себя, то я могу гарантировать что там нет множественного виртуального наследования;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Лучше чем что?

(a.*p)[3]

По такому коду однозначно детектится ООП головного мозга в терминальной стадии.

По такому коду однозначно детектится профессиональный программист, который отличается от хакира-борщевика сакральным знанием того, что на чтение кода уходит на порядок больше времени чем на написание. И каждый вотзефак такого типа стоит много денег.

Необходимость выковыривания смещения члена класса — однозначный признак того, что архитектор — мудак.

anonymous
()
Ответ на: комментарий от ilovewindows
struct A{ double x[10], y; };

void out(A& a, double A::*p){ printf("%g\n", a.*p); }

A * arr = ...;
for(...) out(arr[i], &A::y);
for(...) out(arr[i], get_ptr(&A::x, 4));

на самом деле все намного запутанней;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

для тру

Вообще говоря, наприсанное — UB. На практике, начиная с -O2 GCC не постесняется переставить «pu.ptr = (T A::*)ptr;» и «pu.offset += i*sizeof(T);» местами

anonymous
()
Ответ на: комментарий от anonymous

Теперь подумайте, что делать если известно поле класса, но еще неизвестен экземпляр (его просто нету пока).

По такому коду однозначно детектится профессиональный программист,

Ога, Ога. Меня всегда умиляла эта гордость от принадлежности к касте. Есть нюанс - в наших задачах про. программисты нафик ненужны, от них нет никакого толку. Все чему их учат крайне полезно и помогает при работе в большой команде, и очень мешает при разработке наукоемкого кода в группе из макс. трех человек. Когда приходит студент с задатками проф. программиста заложенными на младших курсах, его приходится долго бить по рукам что бы не писал геттеров/сеттеров, не сносил строку после каждой инструкции и скобки и т.д. Потому что в нашей области свой код читаешь в основном ты сам, гораздо реже такие же мудаки, но никогда проф. программисты. Потому что проф. программисты не знают нихера предметной области, и как бы не был отформатирован код, как бы не был он прекрасен с т.з. какононов проф. программирования, проф программист все равно в нем нихера не поймет. Это не браузеры писать, задачи очень специфические.

AIv ★★★★★
() автор топика
Ответ на: для тру от anonymous

На практике - не переставляет, я проверял. Не надо думать что конпелятор дурней чем есть на самом деле.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Меня всегда умиляла эта гордость от принадлежности к касте.

Не надо тут. В тебе гордости от принадлежности к касте уж точно не меьше %)

я могу гарантировать

Famous last words #2

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

В тебе гордости от принадлежности к касте уж точно не меьше %)

Но я же не чморю проф. программистов за то что у них в игрульках лазерный луч в вакууме летит со скоростью 100м/c;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Но я же не чморю проф. программистов за то что у них в игрульках лазерный луч в вакууме летит со скоростью 100м/c;-)

Прогеры не при делах, это требование дизайнеров. Так красивее. И синий космос - тоже не к нам %)

tailgunner ★★★★★
()
Ответ на: комментарий от AIv

Теперь подумайте, что делать если известно поле класса, но еще неизвестен экземпляр (его просто нету пока).

Вы должны мне новый парсер... В общем случае ответ — «шаблоны», но я подозреваю, что ваша проблема намного серьёзнее.

Ога, Ога. Меня всегда умиляла эта гордость от принадлежности к касте.

Это не гордость, а усталые вздохи и потирание синяков от фейспалмов...

его приходится долго бить по рукам что бы не писал геттеров/сеттеров

Доооо. Надо писать (char *)(this) + &(A::x). В действительности, возле большинства геттеров/сеттеров (в частности, возле приведённого мной) надо писать комментарий вида «У меня необратимое поражение той части мозга, которая отвечает за правильную декомпозицию. Но я не настолько упорот чтобы выдёргивать указатели на члены».

anonymous
()
Ответ на: комментарий от anonymous

В общем случае ответ — «шаблоны»

Шаблоны ответ универсальный, но не на этот вопрос как ни странно.

Это не гордость, а усталые вздохи и потирание синяков от фейспалмов...

Вы никогда не задумывались, что требования к коду (и фейспалмы) сильно зависят от задач?

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Сейчас задумываюсь, что вы путаете требования к кодинг стайлу с требованиями к производительности. Это довольно перпендикулярные вещи. В частности, разница между «double *GetXRef() { return x; }» и вашей конструкцией врядли измерима. А проблемы с dataflow, которые могут давать вполне измеримые значения, налицо.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.