Здравствуйте, 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 году уже что-то есть в стандарте, что я мог запросто пропустить. В моём случае это будет из пушки по воробьям.
Спасибо за развернутый ответ, думаю, я определился с вариантом.