Re[2]: Метод класс как С колбек
От: AHOHUM  
Дата: 09.04.15 10:41
Оценка: +1
Здравствуйте, uzhas, Вы писали:

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


AHO>>Имеется С библиотека с неизменяемым интерфейсом, одна из функций выглядит так:

AHO>>internalState – сугубо внутренняя структура библиотеки, data – данные получаемые из библиотеки, т.е. никаких void * userData нет.

U>обычно в C библиотеках дают возможность просунуть void* userData, поищите внимательнее, либо сообщите название библиотеки, чтобы мы убедились


AHO>>Не могу понять, возможно ли здесь воспользоваться лямбдой или bind(оба параметра: internalState, data — должны быть доступны):


U>по задумке нельзя. лямбды можно скастить к указателю на функцию только если она не захватывает никаких переменных в контекст


AHO>>В чём загвоздка?


U>на самом деле ваша проблема довольно распространена и существует несколько подходов для ее решения

U>1) заводим глобальную переменную, кладем туда this, пишем глобальную функцию, которая имеет сигнатуру Callback и которая при вызове сделает перевызов thisObject->CallbackMethod()
U>2) глобальную переменную еще можно держать в TLS
U>3) зоопарк переменных можно зашаблонить
U>
U>typedef void(*ExtendedCallback)(void * internalState, Data * data, void* userData);

U>template <typename tag>
U>struct CallbackHolder
U>{
U>  static void Func(void * internalState, Data * data)
U>  {
U>    UserCallback(internalState, data, UserData);
U>  }

U>  static void* UserData = nullptr;
U>  static ExtendedCallback UserCallback = nullptr;
U>}

U>//usage
U>struct MyTag1 {} ;// create any number of tags
U>//probably, we need to define static data
U>void* CallbackHolder<MyTag1>::UserData = nullptr;
U>ExtendedCallback CallbackHolder<MyTag1>::UserCallback = nullptr;

U>Callback<MyTag1> c; // track lifetime as needed
U>Callback fn = &Callback<MyTag1>::Func;
U>addCallback(state, fn);
U>


U>4) заморачиваемся с динамическими колбеками-трамплинами. их можно поддерживать динамически или сразу выделить пул из 100 колбеков. рекомендую гуглить по словам trampoline, thunk

U>на этом форуме тоже замечательно гуглится: http://rsdn.ru/forum/cpp.applied/5116247.flat
Автор: uzhas
Дата: 28.03.13

U>суть thunk в том, что он содержит секцию для хранения void* (доп данных) + расширенный колбек и содержит ассемблерный код, который перевызывает расширенный кол-бек со всеми данными
U>метакод
U>
U>typedef void(*ExtendedCallback)(void * internalState, Data * data, void* userData);

U>struct ThunkData
U>{
U>  <executable code>
U>  void* UserData;
U>  ExtendedCallback UserCallback;
U>};

U>ThunkData* data = ...; <- get from pool or allocate somehow
data->>UserData = myData;
data->>UserCallback = mySuperCallback;
U>Callback fn = (Callback)(data); <--- pointer to executable code inside thunk
U>addCallback(state, fn);
U>


U>есть предложения в стандарт языка добавить поддержку таких thunk (ссылку не могу найти)

U>успехов

К сожалению, библиотека коммерческая, и мне категорически намекнули никуда её не выкладывать.
Внимательно поискал: ни в internalState, ни в data – нет места для сохранения указателя на объект класса. internalState имеет комментарий "internally used data" (и оно действительно так и есть, если более детально взглянуть на данную структуру), data содержит строго типизированные данные, которые ожидаются от библиотеки.

1) Вот от этого и хотел уйти, т.к. думал, что есть более "красивые" методы решения данной проблемы.
2) Тоже рассматривал как вариант.
3) Видимо это и буду использовать.
3) Да, конечно, я предварительно загуглил данную тему здесь, нашёл замечательную статью 2004 года. Просто вполне отдавал себе отчёт, что к 2015 году уже что-то есть в стандарте, что я мог запросто пропустить. В моём случае это будет из пушки по воробьям.

Спасибо за развернутый ответ, думаю, я определился с вариантом.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.