Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.92/13: Рейтинг темы: голосов - 13, средняя оценка - 4.92
5232 / 3204 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
1

Std::function<>::target() возвращает 0

19.07.2014, 17:52. Показов 2670. Ответов 11
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Привет!
Не удовольствия для, а фриланса ради пришлось работать с WinAPI. Всем известно, что это чистый С. Так вот захотел я привязать callback процедуру к объекту и скормить это дело API.
C++
1
2
std::function<BOOL CALLBACK (HWND, UINT, WPARAM, LPARAM)> proc = std::bind(&dialog::dialogProc, this, _1, _2, _3, _4);
DialogBoxIndirect(NULL, (LPDLGTEMPLATE)hgbl,    NULL,   (DLGPROC)*proc.target<DLGPROC>());
где DLGPORC это вот такой typedef
C++
1
typedef INT_PTR (CALLBACK* DLGPROC)(HWND, UINT, WPARAM, LPARAM);
Сама callback ф-ция у меня такая
C++
1
BOOL CALLBACK dialog::dialogProc(const dialog *dlg, HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam){}
Проблема в том, что proc.target<>() возвращает 0. Не могу понять в чем проблема, может будут какие-нибудь идеи?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.07.2014, 17:52
Ответы с готовыми решениями:

Class member function to std::function
Всем привет. Вопрос: почему 43 строка не работает? #include &lt;functional&gt; #include &lt;iostream&gt;...

Std::function vs auto Скотт Мэйерс
Доброго времени суток, Господа. Тут перечитывал на досуге Мэйерса, он говорит, что std::function,...

Проблема с заданием шаблона метода с параметром const std::function<T()>
Доброго времени суток! Ткните пожалуйста носом, что не так с заданием шаблона? Компилятор ругается...

Не могу разобраться как обновить в std::map<std::string, вектор_структур>
Не могу разобраться как обновить вектор структур после его добавления в map без удаления и...

11
What a waste!
1610 / 1302 / 180
Регистрация: 21.04.2012
Сообщений: 2,733
19.07.2014, 20:55 2
Цитата Сообщение от Kastaneda Посмотреть сообщение
proc.target<>() возвращает 0
Мне кажется хранимый тип в proc - это не DLGPROC, а тип, генерируемый std::bind.
1
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
19.07.2014, 23:36 3
Цитата Сообщение от Kastaneda Посмотреть сообщение
Не могу понять в чем проблема, может будут какие-нибудь идеи?
CALLBACK должен быть статической функцией класса или свободной функцией.
Как ты себе представляешь в противном случае сохранение контекста this при таком преобразовании:
Цитата Сообщение от Kastaneda Посмотреть сообщение
C++
1
(DLGPROC)*proc.target<DLGPROC>()
?
0
28 / 23 / 12
Регистрация: 25.08.2013
Сообщений: 44
19.07.2014, 23:41 4
Kastaneda, нельзя просто так передать в Вин АПИшную функцию метод класса и никакой бинд тут не поможет. Можно воспользоваться тем свойством, что лямбды без захвата конвертируются в обычную функцию, которую передать не проблема.

Например это может выглядеть так:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
    DLGPROC 
    callback =
    [] ( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )->INT_PTR
  {
    if ( uMsg == WM_CLOSE )
      return EndDialog( hwndDlg, 0 );
    return false;
  };
 
  INT_PTR err = DialogBoxIndirectParamA( NULL, (LPCDLGTEMPLATE)hDialogTemplate, NULL, callback, 0 );
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
19.07.2014, 23:54 5
Kastaneda, короче говоря, сигнатура функции, которая получается через target должна полностью соответствовать сигнатуре сохраненной в std::function. Если ты сохранил одно (метод класса), а пытаешься получить другое (указатель на свободную функцию), то поэтому и возвращается ноль.

Добавлено через 6 минут
StailGot, Я, честно говоря, не очень хорошо знаю это API, но я точно знаю, что в нормальном API с коллбэками должен быть способ передачи контекста (обычно делают void * параметр с user data). Насколько я понял, Kastaneda вступил на этот узкий путь именно из-за необходимости передачи контекста (this). Твое решение с лямбдой эту проблему не решает. Можешь подсказать, возможно ли передать контекст в этом API?
0
28 / 23 / 12
Регистрация: 25.08.2013
Сообщений: 44
20.07.2014, 00:43 6
Лучший ответ Сообщение было отмечено Kastaneda как решение

Решение

DrOffset, DialogBoxIndirect - это макрос для DialogBoxIndirectParam (и это тоже макрос), где последним передается пользовательский параметр, LPARAM dwInitParam, в который передается при первом же вызове callbac'a, событие WM_INITDIALOG. Тут же он просто равен нулю. Так что да, если передать указатель (this), преобразовав его в LPARAM и потом обратно привести к классу, то должно получится. Тут кстати лямбда и пригодится.

Добавлено через 12 минут
Пример передачи строки, с классом примерно тоже самое:

C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  std::string str = "Outer string";
 
  DLGPROC 
    callback =
    [] ( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )->INT_PTR
  {
    if (uMsg == WM_INITDIALOG)
      std::cout << uMsg<< " "<< (*((std::string*)lParam)) << std::endl;
 
    if ( uMsg == WM_CLOSE )
      return EndDialog( hwndDlg, 0 );
    return false;
  };
 
  INT_PTR err = DialogBoxIndirectParamA( NULL, (LPCDLGTEMPLATE)hDialogTemplate, NULL, callback, (LPARAM)&str );
2
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
20.07.2014, 01:18 7
Цитата Сообщение от StailGot Посмотреть сообщение
где последним передается пользовательский параметр, LPARAM dwInitParam, в который передается при первом же вызове callbac'a
А как быть с последующими вызовами? Если, например, на событие WM_CLOSE захочется вызвать какой-то метод класса? Собственно именно поэтому я и не стал предлагать автору решение через этот параметр (естественно я посмотрел MSDN прежде чем спрашивать тебя). Или, все-таки, я чего-то недопонял?
0
28 / 23 / 12
Регистрация: 25.08.2013
Сообщений: 44
20.07.2014, 01:32 8
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
20.07.2014, 03:20 9
Цитата Сообщение от StailGot Посмотреть сообщение
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
К сожалению это решение с большим количеством недостатков. Ну да ладно, пусть автор решает подойдет ему или нет.
0
5232 / 3204 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
20.07.2014, 11:49  [ТС] 10
Спасибо за ответы. Да, моя цель была в том, чтобы протащить this в процедуру. С новыми фишками С++11 плотно не работал, поэтому и сделал такую глупость.
Ладно, раз по человечески это сделать не получится, тогда буду строгать костыль пойду обходным путем

Добавлено через 4 минуты
StailGot, спасибо за пример, я с WinAPI тоже не много работал, поэтому не знал такого.
Цитата Сообщение от StailGot Посмотреть сообщение
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
Думаю логичней всего будет сделать статичный vector<pair<HWND, dialog&>>, куда в процедуре при первом вызове сохранять this, привязанный к хенделу диалога. Таким образом можно будет получить нужный this в любое время.
0
Ушел с форума
Эксперт С++
16478 / 7441 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
20.07.2014, 12:18 11
Цитата Сообщение от DrOffset Посмотреть сообщение
А как быть с последующими вызовами? Если, например, на событие WM_CLOSE захочется вызвать какой-то метод класса?
Цитата Сообщение от Kastaneda Посмотреть сообщение
Думаю логичней всего будет сделать статичный vector<pair<HWND, dialog&>>, куда в процедуре при первом вызове сохранять this, привязанный к хенделу диалога. Таким образом можно будет получить нужный this в любое время.
В обработчике WM_INITDIALOG запомнить переданный в lParam указатель
через SetWindowLongPtr с кодом GWLP_USERDATA. Потом в любом обработчике
его можно извлечь через GetWindowLongPtr с этим же кодом.
1
5232 / 3204 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
20.07.2014, 12:20  [ТС] 12
Убежденный, спасибо, я как раз писать сел)
0
20.07.2014, 12:20
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
20.07.2014, 12:20
Помогаю со студенческими работами здесь

std::string, std::fstream, ошибка кучи
где то начало вылетать при операции += с локальной переменной std::string. Заменил на свой qString....

Как проинициализировать std::stack<const int> obj ( std::stack<int>{} );
добрый день. вопрос в коде: http://rextester.com/VCVVML6656 #include &lt;iostream&gt; #include...

std::filesystem && std::asio и пр
Пытался найти хоть какие-то сроки включения всего этого в стандарт (так же ожидается lexical_cast,...

[Build error] No rule to make target 'String.o'. Stop.
Здравствуйте! Набросал два файла с кодом вроди все нормально, но при компиляции файла String.h...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru