Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Замыкания C++ и связь с C callback-ми


Автор: jonie 14.1.2011, 10:43
Пусть у нас есть Сишный код:
Код

int newCtx() { return 0;}


typedef void (*cbtype)(int ctx);
void RegisterCallback(cbtype callback)
{
  callback(0);  //вызываем
}


и нам надо такой код превратить в класс С++ (стандартная, кстати задача):
Код

class Ctx{
private:
  int m_ctx;
public:
  Ctx() { m_ctx = newCtx();}
  Start() {
   //(1) мы тут должны зарегистрировать обработчик callback
  }
};


В коде в месте (1) нам нужно начать работу с callback. Естественно, что указанный калбэк должен быть статическим и тем самым в непосредственно реализации этой функции мы не имеем this.


Вопрос: как сделать так, чтобы в нашем callback мы могли бы получить this того объекта, который производил регистрацию? *


*) например в C# можно использовать замыкания вроде
Код

class some {
 public Start() {
  var callback = delegate(int ctx) {
    this.foo(); //"затягиваем" this в делегат
  }
  
  register(callback);
 }
}

Но как такое сделать в C++ при указанный условиях что-то не дохожу...

 Недорешение:
мы можем сделать связку сишного контекста (int) с Ctx* используя нечто вроде
Код

static std::map<int, Ctx*> map;
 
и при регистрации в Ctx::Start() добавлять в карту маппинг, но это как-то уныло.


Автор: azesmcar 14.1.2011, 10:48
jonie

А в чем проблема передать this как аргумент в callback например с помощью boost::bind? Конечно, придется немного модифицировать функцию RegisterCallback и сделать ее шаблонной, но думаю ничего страшного.
Код

template <typename F>
void RegisterCallback(F callback) {
   ...
}
...
Start() {
   RegisterCallback(boost::bind(my_callback, this, _1));
}

Автор: mes 14.1.2011, 11:13
Цитата(jonie @  14.1.2011,  09:43 Найти цитируемый пост)
и нам надо такой код превратить в класс С++

все зависит от того где регистрируется колбяк и как нужно это отразить на множество объектов.. 
обычно в С делают доп параметр void*, вот его для thisa можно использовать..желательно только сам метод разгрузить через статическую функцию.. 

Цитата(jonie @  14.1.2011,  09:43 Найти цитируемый пост)
например в C# можно использовать замыкания вроде

Цитата(jonie @  14.1.2011,  09:43 Найти цитируемый пост)
Пусть у нас есть Сишный код:

в таком случае Ваше замыкание не подойдет  smile 
а так в C++ есть (boost::/ std:: ) function и bind для организации замыканий..

Добавлено через 2 минуты и 38 секунд
Цитата(azesmcar @  14.1.2011,  09:48 Найти цитируемый пост)
Конечно, придется немного модифицировать функцию RegisterCallback и сделать ее шаблонной, но думаю ничего страшного.

шаблонной не обязательно..  smile 
но насколько я понял, колбяк нужен для Си-функции, тогда эти методы отпадают..

Добавлено через 4 минуты и 34 секунды
вот пример по этой теме :
http://liveworkspace.org/code/f3ee5f16c898d92b8b005f46d06d1339
из соседней темы :
http://forum.vingrad.ru/forum/topic-320038.html

Автор: jonie 14.1.2011, 11:34
ага, callback нужен для сишной функции и только для неё. Модифицировать Сишный код никак нельзя.
void* userObject - такого Сишная либа не предусматривает (см. выше). Еслиб можно  было - не было бы проблем - именно как тут http://liveworkspace.org/code/f3ee5f16c898d92b8b005f46d06d1339 яб  и сделал не думая 8)
Еще раз для понимая: всё что есть это контекст, который также создается Си либой. И это внутренее "нечто" этой либы.

Цитата(mes @  14.1.2011,  11:13 Найти цитируемый пост)

в таком случае Ваше замыкание не подойдет  smile 

если говорить про C# код, то подойдет и будет работать. Я вроде не ошибаюсь в этом месте...

Еще варианты?

Вот тут чувак пишет что ниче у меня не выйдет (первый ответ): http://stackoverflow.com/questions/2001604/class-member-function-as-callback-using-boostbind-and-boostfunction

Автор: mes 14.1.2011, 11:38
Цитата(jonie @  14.1.2011,  10:34 Найти цитируемый пост)
если говорить про C# код

так Вам для Сишной функции надо то  smile 

так какие параметры предусмотрены ? если никаких, то по какому принципу отражать на множество объектов ?
а если нужно на один, то решается просто - заведите статическую переменную под нужный this..

Добавлено @ 11:44
Цитата(jonie @  14.1.2011,  10:34 Найти цитируемый пост)
Вот тут чувак пишет что ниче у меня не выйдет (первый ответ): 

там Вы привели совсем другую функцию..  smile  но то что Вы написали MyТype ничего не говорит..
для ответа на ваш вопрос нужно знать, что есть эти параметры на самом деле.. 
в общем Вам нужно определить есть ли среди параметров такой, вместо которого можно подсунуть this...




Автор: jonie 14.1.2011, 11:45
Цитата(mes @  14.1.2011,  11:38 Найти цитируемый пост)

так какие параметры предусмотрены ? если никаких, то по какому принципу отражать на множество объектов ?
никаких, увы..

Цитата(mes @  14.1.2011,  11:38 Найти цитируемый пост)

а если нужно на один, то решается просто - заведите статическую переменную под нужный this.. 

этот метод я описывал в топике под именем "Недорешение" ..

ну да, наверно иначе и никак не получится... ведь в функции я действительно никак не узнаю о this как бы не старался.

Хотя C# вот как-то выкручивается.. надо почитатьс как он это делает. Наверно такой же метод использует в конечном итоге.

Автор: mes 14.1.2011, 11:50
Цитата(jonie @  14.1.2011,  10:45 Найти цитируемый пост)
никаких, увы..

тогда нужно определиться :
Цитата(mes @  14.1.2011,  10:38 Найти цитируемый пост)
 по какому принципу отражать на множество объектов ?




Цитата(jonie @  14.1.2011,  10:45 Найти цитируемый пост)
этот метод я описывал в топике под именем "Недорешение" ..

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

Автор: mes 14.1.2011, 12:17
Цитата(mes @  14.1.2011,  10:50 Найти цитируемый пост)
тогда нужно определиться :
Цитата(mes @  14.1.2011,  10:38 )
 по какому принципу отражать на множество объектов ?

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

вот пример для размышления и допиливания под свои нужды :
http://liveworkspace.org/code/47d75b234a075cd3e8c569f74af6a251

Автор: jonie 14.1.2011, 12:19
ну я собственно так и сделал у себя, но мне чет не особо понравилось 8)

Автор: mes 14.1.2011, 12:20
Цитата(jonie @  14.1.2011,  11:19 Найти цитируемый пост)
 но мне чет не особо понравилось 

ну а поконкретней, чего не понравилось то ?

Добавлено через 3 минуты и 34 секунды
Цитата(jonie @  14.1.2011,  11:19 Найти цитируемый пост)
ну я собственно так и сделал у себя, 

если Вы об этом
Цитата(jonie @  14.1.2011,  09:43 Найти цитируемый пост)
мы можем сделать связку сишного контекста (int) с Ctx* используя нечто вроде

то это совсем другое.. в примере нет (ран-тайм) карты и ассоциация метода идет к адресу функции колбяка... 

Автор: mes 14.1.2011, 12:54
вот еще вариантик:
http://liveworkspace.org/code/eddee3669c8a4eb3414f172d741cf696

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

Автор: azesmcar 14.1.2011, 13:29
Цитата(jonie @  14.1.2011,  11:34 Найти цитируемый пост)
Модифицировать Сишный код никак нельзя.

т.е. даже добавлять аргумент в callback нельзя? тогда единственный вариант - получить указатель из какого нибудь глобального контейнера, т.е.

Цитата(jonie @  14.1.2011,  10:43 Найти цитируемый пост)
Недорешение

 smile 

Автор: jonie 14.1.2011, 13:29
Цитата(mes @  14.1.2011,  12:20 Найти цитируемый пост)

если Вы об этом
Цитата

Цитата(jonie @  14.1.2011,  09:43 Найти цитируемый пост)
мы можем сделать связку сишного контекста (int) с Ctx* используя нечто вроде


то это совсем другое.. в примере нет (ран-тайм) карты и ассоциация метода идет к адресу функции колбяк

ну это понятно. Я имел в виду что в общем связь хранится в неком статической внешней (по отношениею к создавающему объекту) переменной. А вот что хранится  ней: указатель ли на объект или указатель на функцию в этом объекте на самом деле не важно.

этак можно  и до boost::signals2 дойти )

Автор: mes 14.1.2011, 13:45
Цитата(jonie @  14.1.2011,  12:29 Найти цитируемый пост)
. Я имел в виду что в общем связь хранится в неком статической внешней (по отношениею к создавающему объекту) переменной.

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

Добавлено через 2 минуты и 51 секунду
Цитата(jonie @  14.1.2011,  12:29 Найти цитируемый пост)
й. А вот что хранится  ней: указатель ли на объект или указатель на функцию в этом объекте на самом деле не важно.

это да.. вопрос не в том, что хранится, а к чему ассоциировано то, что хранится..

Добавлено через 5 минут и 10 секунд
Цитата(jonie @  14.1.2011,  12:29 Найти цитируемый пост)
 внешней (по отношениею к создавающему объекту) 

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


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)