Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: Aleksey82  
Дата: 26.04.21 20:10
Оценка: :)))
Допустим у нас есть библиотечный класс, у которого есть функция, которая принимает указатель на функцию в качестве коллбэка

typedef void (*pfnCallback)(int param);

class XY
{
public:
void setCallback(pfnCallback callback);
}


Т.е. мы в экземляр класса XY сеттим коллбэк, который является обычной функцией, не членом, и при ее вызове нам не передается указатель того объекта, который ее вызвал.

Задача: при вызове pfnCallback, в ее теле, нам надо узнать какой из объектов XY ее сейчас вызвал.

Кода XY у нас нет и изменить мы его не можем, мы пишем ту прослойку которая ставит в экземпляры XY коллбэки. Вот тело коллбэка мы можем менять как угодно. Можно использовать глобальные переменные и тд. Решение должно быть кроссплатформенное — винда, линукс, андроид, и для каждой ОС там должны поддерживаться все компиляторы которые могут C++11
Re: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: a7d3  
Дата: 26.04.21 20:33
Оценка: +2 -1 :))) :)
Здравствуйте, Aleksey82, Вы писали:

A>Кода XY у нас нет и изменить мы его не можем, мы пишем ту прослойку которая ставит в экземпляры XY коллбэки. Вот тело коллбэка мы можем менять как угодно. Можно использовать глобальные переменные и тд. Решение должно быть кроссплатформенное — винда, линукс, андроид, и для каждой ОС там должны поддерживаться все компиляторы которые могут C++11


Ответил бы, да сильно не понравилась тональность поста. Очень уже отвык от приказного начальственного тона во всяких «красных компаниях».
Создалось впечатление, что очередной тимлид из тех, что сперва по дурости своей разгонят всех квалифицированных специалистов, оставив вокруг себя одних «собак», а потом по форумам лазают с вопросами по элементарным вещам.
Re: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: cserg  
Дата: 26.04.21 20:44
Оценка:
Здравствуйте, Aleksey82, Вы писали:

A>Задача: при вызове pfnCallback, в ее теле, нам надо узнать какой из объектов XY ее сейчас вызвал.

А что экземпляр класса XY передает в int param вашему коллбэку? Из этого значения нельзя выудить экземпляр XY?
Re: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: kov_serg Россия  
Дата: 26.04.21 20:47
Оценка: 4 (1)
Здравствуйте, Aleksey82, Вы писали:

A>Т.е. мы в экземляр класса XY сеттим коллбэк, который является обычной функцией, не членом, и при ее вызове нам не передается указатель того объекта, который ее вызвал.

A>Задача: при вызове pfnCallback, в ее теле, нам надо узнать какой из объектов XY ее сейчас вызвал.
Типа такого?
#include <stdio.h>

typedef void (*pfnCallback)(int param);

struct XY {
    void setCallback(pfnCallback callback);
};

void XY::setCallback(pfnCallback callback) {
    callback(12345);
}

// code:
typedef void (*fn2_t)(int id,int param);
template<int id> struct CB {
    static pfnCallback create(fn2_t f2) { fn2=f2; return fn; }
    static fn2_t fn2;
    static void fn(int param) { if(fn2) fn2(id,param); }
};
template<int id> fn2_t CB<id>::fn2=0;

// usage:
enum { CLASS0,CLASS1,CLASS2 };
const char* id2name[]={ "CLASS0","CLASS1","CLASS2" };

void cb(int id,int param) {    printf("%s: param=%d\n",id2name[id],param); }

int main(int argc, char const *argv[])
{
    XY x[1];
    x->setCallback(CB<CLASS0>::create(cb));
    x->setCallback(CB<CLASS1>::create(cb));
    x->setCallback(CB<CLASS2>::create(cb));
    return 0;
}
Re[2]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: Aleksey82  
Дата: 26.04.21 20:52
Оценка:
A>>Задача: при вызове pfnCallback, в ее теле, нам надо узнать какой из объектов XY ее сейчас вызвал.
C>А что экземпляр класса XY передает в int param вашему коллбэку? Из этого значения нельзя выудить экземпляр XY?

Нет, там по факту разные классы используют этот механизм, обычно какой-то статус, код ошибки или флаг состояния передают.
Re: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: B0FEE664  
Дата: 26.04.21 20:53
Оценка:
Здравствуйте, Aleksey82, Вы писали:

A>Допустим у нас есть библиотечный класс, у которого есть функция, которая принимает указатель на функцию в качестве коллбэка


A>
A>typedef void (*pfnCallback)(int param);

A>class XY
A>{
A>public:
A>void setCallback(pfnCallback callback);
A>}
A>


A>Т.е. мы в экземляр класса XY сеттим коллбэк, который является обычной функцией, не членом, и при ее вызове нам не передается указатель того объекта, который ее вызвал.

A>Задача: при вызове pfnCallback, в ее теле, нам надо узнать какой из объектов XY ее сейчас вызвал.

А в чём сложность? Создайте по экземпляру сallback'а на каждый set, а внутрь запишите указатель на XY.
И каждый день — без права на ошибку...
Re[2]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: Aleksey82  
Дата: 26.04.21 20:56
Оценка:
BFE>А в чём сложность? Создайте по экземпляру сallback'а на каждый set, а внутрь запишите указатель на XY.

В общем, в том и сложность. Коллбэк это просто сишная функция. Каким образом записать внутрь указатель?
Re[3]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: B0FEE664  
Дата: 26.04.21 21:15
Оценка:
Здравствуйте, Aleksey82, Вы писали:

BFE>>А в чём сложность? Создайте по экземпляру сallback'а на каждый set, а внутрь запишите указатель на XY.


A>В общем, в том и сложность. Коллбэк это просто сишная функция. Каким образом записать внутрь указатель?


На каждый вызов xy.setCallback(..);
пишите функцию callbackNum0001(..);
рядом заводите глобальную переменную XY* xyNum0001;
перед xy.setCallback(..); в xyNum0001 записываете указатель на xy, которую используете в callbackNum0001(..)
Если xy не создаются динамически, то никаких проблем.
И каждый день — без права на ошибку...
Re[3]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: kov_serg Россия  
Дата: 26.04.21 21:15
Оценка: 4 (1)
Здравствуйте, Aleksey82, Вы писали:

BFE>>А в чём сложность? Создайте по экземпляру сallback'а на каждый set, а внутрь запишите указатель на XY.


A>В общем, в том и сложность. Коллбэк это просто сишная функция. Каким образом записать внутрь указатель?

Сделайте динамически.
#include <stdio.h>

typedef void (*pfnCallback)(int param);

struct XY {
    void setCallback(pfnCallback callback);
};

void XY::setCallback(pfnCallback callback) {
    callback(12345);
}

// dynamic:
struct CB2 {
    enum { limit=8 }; // разумное количество
    typedef void (*cb_t)(void *ctx,int param);
    struct map_t { pfnCallback cb0; cb_t cb; void *ctx; };
    static int count;
    static map_t map[limit];
    static pfnCallback alloc(cb_t cb,void *ctx) { // при желании можно и освобождение сделать и многопоточность если надо
        if (count>=limit) return 0;
        map[count].cb=cb;
        map[count].ctx=ctx;
        return map[count++].cb0;
    }
    template<int i>static void fn(int param) { map[i].cb(map[i].ctx,param); }
    template<class T,void (T::*M)(int)>static void member(void* ctx,int param) { T* t=(T*)ctx; (t->*M)(param); }
};

int CB2::count=0;
CB2::map_t CB2::map[]={
    {CB2::fn<0>},{CB2::fn<1>},{CB2::fn<2>},{CB2::fn<3>},
    {CB2::fn<4>},{CB2::fn<5>},{CB2::fn<6>},{CB2::fn<7>} // можно скриптом нагенерить или макросами
};

// usage:
struct A { void cb(int param) { printf("A.param=%d\n",param); } };
static void A_cb(void* ctx,int param) {    
    A* p=(A*)ctx;
    p->cb(param);
}
struct B { int id; void hit(int param) { printf("B%d.param=%d\n",id,param); } };

int main(int argc, char const *argv[]) {
    XY x[1]; A a[1]; B b[2]={ {0},{1} };

    x->setCallback( CB2::alloc(A_cb,a) );
    x->setCallback( CB2::alloc(CB2::member<A,&A::cb>,a) );
    x->setCallback( CB2::alloc(CB2::member<B,&B::hit>,&b[0]) );
    x->setCallback( CB2::alloc(CB2::member<B,&B::hit>,&b[1]) );
    return 0;
}
Re[4]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: Aleksey82  
Дата: 26.04.21 21:31
Оценка:
BFE>На каждый вызов xy.setCallback(..);
BFE>пишите функцию callbackNum0001(..);
BFE>рядом заводите глобальную переменную XY* xyNum0001;
BFE>перед xy.setCallback(..); в xyNum0001 записываете указатель на xy, которую используете в callbackNum0001(..)
BFE>Если xy не создаются динамически, то никаких проблем.

В этом и проблема, объекты xy создаются динамически в произвольных количествах.
Re[4]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: Aleksey82  
Дата: 26.04.21 21:32
Оценка:
A>>В общем, в том и сложность. Коллбэк это просто сишная функция. Каким образом записать внутрь указатель?
_>Сделайте динамически.

Да, спасибо, я заплюсовал ваш ответ, сейчас пробую. Вроде как ваше решение должно работать)
Re[5]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: B0FEE664  
Дата: 26.04.21 21:54
Оценка: +3
Здравствуйте, Aleksey82, Вы писали:

A>В этом и проблема, объекты xy создаются динамически в произвольных количествах.


Насколько я понимаю, в рамках С++ такая задача не решаема: не существует способа динамически создать копию функции. Так что либо вы заранее создаёте 100500 функций, как предлагает рядом kov_serg, либо выходите за рамки стандарта и начинаете писать грязные хаки.

Чисто из любопытства, а зачем вам все эти извращения? Почему нормально нельзя сделать?
И каждый день — без права на ошибку...
Re[6]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: Zhendos  
Дата: 27.04.21 07:05
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Здравствуйте, Aleksey82, Вы писали:


BFE>Чисто из любопытства, а зачем вам все эти извращения? Почему нормально нельзя сделать?


Не автор, но первое что приходит на ум это win32 API.
Часть колбеков там не используют что-то типа "void *context",
поэтому кто не хочет иметь кучу глобальных переменных извращается как может.

ATL библиотека от MS например генерировала на лету машинный код
например, типа:
struct Thunk {
  BYTE    jmp;  // op code of jmp instruction
  DWORD   relproc; // relative jmp address
};
Re[2]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: TimurSPB Интернет  
Дата: 27.04.21 08:44
Оценка: +1 :)))
A>Ответил бы, да сильно не понравилась тональность поста.
Отличная формулировка. Буду тестерам пункты возвращать с такой фразой.
Make flame.politics Great Again!
Re[3]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: a7d3  
Дата: 27.04.21 12:12
Оценка:
Здравствуйте, TimurSPB, Вы писали:

A>>Ответил бы, да сильно не понравилась тональность поста.

TSP>Отличная формулировка. Буду тестерам пункты возвращать с такой фразой.

Тащить с интернет-форумов в работу и взаимодействии с коллегами? Это кривая дорожка, однозначно

За хамство и грубость в отношении тестеров увольнять следует в первую очередь. Во-вторую, за подобное по отношению к непосредственным подчинённым или обслуживающему персоналу.

Да, в интернетах могут и на х.. послать, но в общении с коллегами — это недопустимо.
Re: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: cppguard  
Дата: 28.04.21 03:19
Оценка:
Здравствуйте, Aleksey82, Вы писали:

A>Решение должно быть кроссплатформенное — винда, линукс, андроид, и для каждой ОС там должны поддерживаться все компиляторы которые могут C++11


Не вопрос, босс — $100 за консультацию, и решение у вас в кармане.
Re[2]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: Pzz Россия https://github.com/alexpevzner
Дата: 28.04.21 07:49
Оценка: 1 (1)
Здравствуйте, cppguard, Вы писали:

A>>Решение должно быть кроссплатформенное — винда, линукс, андроид, и для каждой ОС там должны поддерживаться все компиляторы которые могут C++11


C>Не вопрос, босс — $100 за консультацию, и решение у вас в кармане.


Хм. Сделать это надежно и чтобы везде работало гораздо больше, чем $100 стоит. За $100 я бы дал совет, этого не делать
Re[3]: Как из тела функции понять кто ее вызвал? (придумать С++ механизм)
От: Pzz Россия https://github.com/alexpevzner
Дата: 28.04.21 07:50
Оценка:
Здравствуйте, TimurSPB, Вы писали:

A>>Ответил бы, да сильно не понравилась тональность поста.

TSP>Отличная формулировка. Буду тестерам пункты возвращать с такой фразой.

Это надо на собеседованиях говорить, когда предлагают тестовое задание.
Re: Как из тела функции понять кто ее вызвал? (придумать С++
От: Reset  
Дата: 28.04.21 22:03
Оценка:
Тут была всякая фигня, не относящаяся к вопросу ТС.
Отредактировано 29.04.2021 12:51 Reset . Предыдущая версия . Еще …
Отредактировано 28.04.2021 22:05 Reset . Предыдущая версия .
Re[2]: Как из тела функции понять кто ее вызвал? (придумать С++
От: cserg  
Дата: 29.04.21 07:12
Оценка:
Здравствуйте, Reset, Вы писали:

R>... Для всех 3 комбинаций есть backtrace/stacktrace (если задача решается перебором 3 вариантов — то другое решение не ищут).

Что-то я похоже туплю и не понял как backtrace/stacktrace может помочь ТСу? Ему же нухно узнать не какая функция/метод вызвала callback, а какой объект вызвал, т.е. надо анализировать стековые фреймы цепочки вызовов и найти там указатель this. И похоже, что анализировать без наличия отладочной информации, т.к. библиотечный код не его.
Re[3]: Как из тела функции понять кто ее вызвал? (придумать С++
От: Reset  
Дата: 29.04.21 12:50
Оценка:
C>Что-то я похоже туплю и не понял как backtrace/stacktrace может помочь ТСу? Ему же нухно узнать не какая функция/метод вызвала callback, а какой объект вызвал, т.е. надо анализировать стековые фреймы цепочки вызовов и найти там указатель this. И похоже, что анализировать без наличия отладочной информации, т.к. библиотечный код не его.

Опс, ошибочка вышла. Невнимательно прочитал. Какой объект вызвал функцию, так, похоже, не узнать.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.