class A
{
public:
void m (void)
{
//...
};
};
typedef void (*pa)(void);
typedef void (A::*pma)(void);
void someforeignfunc(pa) // <-- вот это менять нельзя
{
//...
}
A a;
void main ()
{
someforeignfunc(/*???*/); // <-- как вот здесь подсунуть указатель на a.m?
}
Как в someforeignfunc отдать указатель на a.m не используя интерфейсов вроде
void f()
{
a.m();
}
Очевидное решение — изменить someforeignfunc так, чтобы принимала pma, но эта функция "не моя".
Понимаю, что никак, но надеюсь, что ошибаюсь
Здравствуйте, MTimur, Вы писали:
MT>Очевидное решение — изменить someforeignfunc так, чтобы принимала pma, но эта функция "не моя". MT>Понимаю, что никак, но надеюсь, что ошибаюсь
Можно с рядом ограничений.
1) Синглетон
// присвой нужные значения перед вызовомstatic A* object;
static pma method;
void invoke() { (object->*method)(); }
Нельзя одновременно создавать произвольное количество РАЗНЫХ замыканий.
Хотя, можно завести пул функций invoke1, invoke2, ... — и для каждой свой комплект статических данных.
2) Санки
struct Thunk
{
char bytecode[XZ];
void generate(A* object, pma method)
{
// здесь рожаем байткод для функции invoke()
// в который подставляем значения object и method
}
pa get_invoke() { return (pa)bytecode; }
};
Это платформенно-зависимый подход. Для разных процессоров — разная реализация.
Используется в ATL, кстати. Можно попробовать оттуда выдрать.
Перекуём баги на фичи!
Re[2]: Указатель на метод объекта класса. Возможно?
Здравствуйте, Кодт, Вы писали:
К>Нельзя одновременно создавать произвольное количество РАЗНЫХ замыканий. К>Хотя, можно завести пул функций invoke1, invoke2, ... — и для каждой свой комплект статических данных.
Добавлю только, что такой пул можно сгенерировать с помощью шаблонов "для любого конечного N".
Сгенерировать функций заведомо больше, чем должно понадобиться (например, больше, чем кол-во потоков). Дальше брать калбеки из пула и возвращать, ну а если пул оказывается пустой, то кидать исключение, это типа как out-of-memory, ну точнее out-of-resources.
А вот в том то и дело, что не хотелось делать такой обвес.
На самом деле мне нужно передать во внешнюю библиотеку набор callback функций:
typedef void (*pa)(void);
typedef int (*pb)(void);
typedef void (*pc)(int);
typedef void (A::*pma)(void);
struct cb
{
pa a1;
pa a2;
pb b;
pc c;
// и еще пару десятков строк
// ....
}
// cb.a = ...
// cb.b = ...
// ..........
someforeignfunc(cb);
Все эти callback'и реализованы как методы класса. В программе создается один экземпляр этого класса и на момент заполнения структуры cb и вызова someforeignfunc этот экземпляр уже существует. Кроме того он не имеет наследников и сам не является наследником. Т.о. методы этого объекта не отличаются от обычной функции. Верно? Или я ошибаюсь?
Так вот я хотел в структуру cb затолкать указатели на его методы, а не на функции-обвязки указанные выше (f() и invoke()). Для компилятора pa и pma совсем не одно и то же, хотя кажется мне, что разницы в данном случае как бы нет.
Очевидно обмануть компилятор не получится, придется делать внешние функции.
Спасибо.
Re[3]: Указатель на метод объекта класса. Возможно?
Здравствуйте, MTimur, Вы писали:
MT>Все эти callback'и реализованы как методы класса. В программе создается один экземпляр этого класса и на момент заполнения структуры cb и вызова someforeignfunc этот экземпляр уже существует. Кроме того он не имеет наследников и сам не является наследником. Т.о. методы этого объекта не отличаются от обычной функции. Верно? Или я ошибаюсь?
В общем случае ошибаетесь.
Ибо метод объекта для работы хочет this.
А передача этого this осуществляется через какой нить __thiscall calling convention.
Если например рассматривать компилятор от MS и допустить что ваш метод не обращается к полям своего объекта, то ваше предположение будет верно,
в противном случае нет.
Передать указатель то очень просто, даже асм вставок ненужно =)
Но это будет грязнючий хак.
Самое лучшее решение имхо с переходником, как написал Кодт.
П.С. Почемуто вспомнилась милая задачка о получении адреса конструктора произвольного объекта =)
Re[3]: Указатель на метод объекта класса. Возможно?
Здравствуйте, MTimur, Вы писали:
MT>А вот в том то и дело, что не хотелось делать такой обвес. MT>На самом деле мне нужно передать во внешнюю библиотеку набор callback функций: MT>Все эти callback'и реализованы как методы класса.
Это твоя реализация, или так сделана внешняя библиотека?
MT>В программе создается один экземпляр этого класса и на момент заполнения структуры cb и вызова someforeignfunc этот экземпляр уже существует. Кроме того он не имеет наследников и сам не является наследником. Т.о. методы этого объекта не отличаются от обычной функции. Верно? Или я ошибаюсь?
Ошибаешься. Методы классов имеют неявный параметр this (или const this).
Что по твоему должна передать внешняя библиотека в качестве этого параметра?
MT>Так вот я хотел в структуру cb затолкать указатели на его методы, а не на функции-обвязки указанные выше (f() и invoke()). Для компилятора pa и pma совсем не одно и то же, хотя кажется мне, что разницы в данном случае как бы нет. MT>Очевидно обмануть компилятор не получится, придется делать внешние функции.
Ты, кажется, пытаешься изобрести велосипед, под названием интерфейс.
Имею скафандр — готов путешествовать!
Re[4]: Указатель на метод объекта класса. Возможно?
Здравствуйте, unreg_flex, Вы писали:
_>В общем случае ошибаетесь. _>Ибо метод объекта для работы хочет this. _>А передача этого this осуществляется через какой нить __thiscall calling convention. _>Если например рассматривать компилятор от MS и допустить что ваш метод не обращается к полям своего объекта, то ваше предположение будет верно, _>в противном случае нет. _>Передать указатель то очень просто, даже асм вставок ненужно =) _>Но это будет грязнючий хак.
АФАИР, если добавить в функцию-метод ellipsis последним параметром, то и студия и гцц переделывают соглашение о вызове в __cdecl, и тогда её можно передавать как каллбек в С код — this будет выглядеть как первый параметр типа void*.
Здравствуйте, remark, Вы писали:
R>АФАИР, если добавить в функцию-метод ellipsis последним параметром, то и студия и гцц переделывают соглашение о вызове в __cdecl, и тогда её можно передавать как каллбек в С код — this будет выглядеть как первый параметр типа void*.
Красиво
Re[5]: Указатель на метод объекта класса. Возможно?
Подожди, а this-то кто будет передавать в эту функцию? И зачем Ptr, чем это отличается от простого каста одной функции в другую? И размеры их зачастую не равны...
Здравствуйте, remark, Вы писали:
R>Подожди, а this-то кто будет передавать в эту функцию? И зачем Ptr, чем это отличается от простого каста одной функции в другую? И размеры их зачастую не равны...
Я же написал выше, что только если методы не обращаются к полям объекта.
Простой каст вроде как не канает.
Про размеры я в курсе поетому и влепил ассерт, автор поста же написал что объект простой без наследования и как бы прочей хрени.
Я сам бы такое в коде низачто не оставил, просто как я понял у автора скастить как раз и не получалось, но передать хоть как нибудь очень хотелось.
Re[7]: Указатель на метод объекта класса. Возможно?
Здравствуйте, unreg_flex, Вы писали:
_>Здравствуйте, remark, Вы писали:
R>>Подожди, а this-то кто будет передавать в эту функцию? И зачем Ptr, чем это отличается от простого каста одной функции в другую? И размеры их зачастую не равны...
_>Я же написал выше, что только если методы не обращаются к полям объекта. _>Простой каст вроде как не канает. _>Про размеры я в курсе поетому и влепил ассерт, автор поста же написал что объект простой без наследования и как бы прочей хрени. _>Я сам бы такое в коде низачто не оставил, просто как я понял у автора скастить как раз и не получалось, но передать хоть как нибудь очень хотелось.
Всё-таки простой объект без наследования и вообще не обращаться к полям — это разные вещи. А если уж он не обращается к полям, то надо не это городить, а пометить методы как static.