Форум программистов, компьютерный форум CyberForum.ru

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

Войти
Регистрация
Восстановить пароль
 
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4248 / 2780 / 219
Регистрация: 12.12.2009
Сообщений: 7,109
Записей в блоге: 1
Завершенные тесты: 1
19.07.2014, 17:52     Std::function<>::target() возвращает 0 #1
Привет!
Не удовольствия для, а фриланса ради пришлось работать с 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. Не могу понять в чем проблема, может будут какие-нибудь идеи?
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
gray_fox
What a waste!
 Аватар для gray_fox
1246 / 1129 / 54
Регистрация: 21.04.2012
Сообщений: 2,354
Завершенные тесты: 3
19.07.2014, 20:55     Std::function<>::target() возвращает 0 #2
Цитата Сообщение от Kastaneda Посмотреть сообщение
proc.target<>() возвращает 0
Мне кажется хранимый тип в proc - это не DLGPROC, а тип, генерируемый std::bind.
DrOffset
6795 / 4006 / 920
Регистрация: 30.01.2014
Сообщений: 6,830
19.07.2014, 23:36     Std::function<>::target() возвращает 0 #3
Цитата Сообщение от Kastaneda Посмотреть сообщение
Не могу понять в чем проблема, может будут какие-нибудь идеи?
CALLBACK должен быть статической функцией класса или свободной функцией.
Как ты себе представляешь в противном случае сохранение контекста this при таком преобразовании:
Цитата Сообщение от Kastaneda Посмотреть сообщение
C++
1
(DLGPROC)*proc.target<DLGPROC>()
?
StailGot
27 / 22 / 6
Регистрация: 25.08.2013
Сообщений: 41
19.07.2014, 23:41     Std::function<>::target() возвращает 0 #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 );
DrOffset
6795 / 4006 / 920
Регистрация: 30.01.2014
Сообщений: 6,830
19.07.2014, 23:54     Std::function<>::target() возвращает 0 #5
Kastaneda, короче говоря, сигнатура функции, которая получается через target должна полностью соответствовать сигнатуре сохраненной в std::function. Если ты сохранил одно (метод класса), а пытаешься получить другое (указатель на свободную функцию), то поэтому и возвращается ноль.

Добавлено через 6 минут
StailGot, Я, честно говоря, не очень хорошо знаю это API, но я точно знаю, что в нормальном API с коллбэками должен быть способ передачи контекста (обычно делают void * параметр с user data). Насколько я понял, Kastaneda вступил на этот узкий путь именно из-за необходимости передачи контекста (this). Твое решение с лямбдой эту проблему не решает. Можешь подсказать, возможно ли передать контекст в этом API?
StailGot
27 / 22 / 6
Регистрация: 25.08.2013
Сообщений: 41
20.07.2014, 00:43     Std::function<>::target() возвращает 0 #6
Сообщение было отмечено автором темы, экспертом или модератором как ответ
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 );
DrOffset
6795 / 4006 / 920
Регистрация: 30.01.2014
Сообщений: 6,830
20.07.2014, 01:18     Std::function<>::target() возвращает 0 #7
Цитата Сообщение от StailGot Посмотреть сообщение
где последним передается пользовательский параметр, LPARAM dwInitParam, в который передается при первом же вызове callbac'a
А как быть с последующими вызовами? Если, например, на событие WM_CLOSE захочется вызвать какой-то метод класса? Собственно именно поэтому я и не стал предлагать автору решение через этот параметр (естественно я посмотрел MSDN прежде чем спрашивать тебя). Или, все-таки, я чего-то недопонял?
StailGot
27 / 22 / 6
Регистрация: 25.08.2013
Сообщений: 41
20.07.2014, 01:32     Std::function<>::target() возвращает 0 #8
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
DrOffset
6795 / 4006 / 920
Регистрация: 30.01.2014
Сообщений: 6,830
20.07.2014, 03:20     Std::function<>::target() возвращает 0 #9
Цитата Сообщение от StailGot Посмотреть сообщение
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
К сожалению это решение с большим количеством недостатков. Ну да ладно, пусть автор решает подойдет ему или нет.
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4248 / 2780 / 219
Регистрация: 12.12.2009
Сообщений: 7,109
Записей в блоге: 1
Завершенные тесты: 1
20.07.2014, 11:49  [ТС]     Std::function<>::target() возвращает 0 #10
Спасибо за ответы. Да, моя цель была в том, чтобы протащить this в процедуру. С новыми фишками С++11 плотно не работал, поэтому и сделал такую глупость.
Ладно, раз по человечески это сделать не получится, тогда буду строгать костыль пойду обходным путем

Добавлено через 4 минуты
StailGot, спасибо за пример, я с WinAPI тоже не много работал, поэтому не знал такого.
Цитата Сообщение от StailGot Посмотреть сообщение
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
Думаю логичней всего будет сделать статичный vector<pair<HWND, dialog&>>, куда в процедуре при первом вызове сохранять this, привязанный к хенделу диалога. Таким образом можно будет получить нужный this в любое время.
Убежденный
Системный программист
 Аватар для Убежденный
14473 / 6457 / 1020
Регистрация: 02.05.2013
Сообщений: 10,693
Завершенные тесты: 1
20.07.2014, 12:18     Std::function<>::target() возвращает 0 #11
Цитата Сообщение от DrOffset Посмотреть сообщение
А как быть с последующими вызовами? Если, например, на событие WM_CLOSE захочется вызвать какой-то метод класса?
Цитата Сообщение от Kastaneda Посмотреть сообщение
Думаю логичней всего будет сделать статичный vector<pair<HWND, dialog&>>, куда в процедуре при первом вызове сохранять this, привязанный к хенделу диалога. Таким образом можно будет получить нужный this в любое время.
В обработчике WM_INITDIALOG запомнить переданный в lParam указатель
через SetWindowLongPtr с кодом GWLP_USERDATA. Потом в любом обработчике
его можно извлечь через GetWindowLongPtr с этим же кодом.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.07.2014, 12:20     Std::function<>::target() возвращает 0
Еще ссылки по теме:

C++ вызов функции члена через std::function
Сравнение std::function с необходимым каллбеком C++
C++ В std::function передать метод класса
C++ Уточнения сигнатуры функции для std::function

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

Или воспользуйтесь поиском по форуму:
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4248 / 2780 / 219
Регистрация: 12.12.2009
Сообщений: 7,109
Записей в блоге: 1
Завершенные тесты: 1
20.07.2014, 12:20  [ТС]     Std::function<>::target() возвращает 0 #12
Убежденный, спасибо, я как раз писать сел)
Yandex
Объявления
20.07.2014, 12:20     Std::function<>::target() возвращает 0
Ответ Создать тему
Опции темы

Текущее время: 22:16. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru