Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++

Войти
Регистрация
Восстановить пароль
 
Kastaneda
Jesus loves me
Эксперт С++
4689 / 2893 / 236
Регистрация: 12.12.2009
Сообщений: 7,356
Записей в блоге: 2
Завершенные тесты: 1
#1

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

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

Привет!
Не удовольствия для, а фриланса ради пришлось работать с 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)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
19.07.2014, 17:52
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Std::function<>::target() возвращает 0 (C++):

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

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

std::filesystem && std::asio и пр - C++
Пытался найти хоть какие-то сроки включения всего этого в стандарт (так же ожидается lexical_cast, any, string_algo и т.д.) и вообщем везде...

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

std::defaultfloat - C++
Есть такая тема в новом стандарте как std::defaultfloat Описание: http://www.cplusplus.com/reference/ios/defaultfloat/ В стандарте...

переписать std::map - C++
Добрый вечер! Есть работающая программа, в которой используется map, все работало хорошо, но теперь немного изменились условия и объем...

11
gray_fox
What a waste!
1521 / 1226 / 70
Регистрация: 21.04.2012
Сообщений: 2,565
Завершенные тесты: 3
19.07.2014, 20:55 #2
Цитата Сообщение от Kastaneda Посмотреть сообщение
proc.target<>() возвращает 0
Мне кажется хранимый тип в proc - это не DLGPROC, а тип, генерируемый std::bind.
1
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
19.07.2014, 23:36 #3
Цитата Сообщение от Kastaneda Посмотреть сообщение
Не могу понять в чем проблема, может будут какие-нибудь идеи?
CALLBACK должен быть статической функцией класса или свободной функцией.
Как ты себе представляешь в противном случае сохранение контекста this при таком преобразовании:
Цитата Сообщение от Kastaneda Посмотреть сообщение
C++
1
(DLGPROC)*proc.target<DLGPROC>()
?
0
StailGot
28 / 23 / 6
Регистрация: 25.08.2013
Сообщений: 41
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
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
19.07.2014, 23:54 #5
Kastaneda, короче говоря, сигнатура функции, которая получается через target должна полностью соответствовать сигнатуре сохраненной в std::function. Если ты сохранил одно (метод класса), а пытаешься получить другое (указатель на свободную функцию), то поэтому и возвращается ноль.

Добавлено через 6 минут
StailGot, Я, честно говоря, не очень хорошо знаю это API, но я точно знаю, что в нормальном API с коллбэками должен быть способ передачи контекста (обычно делают void * параметр с user data). Насколько я понял, Kastaneda вступил на этот узкий путь именно из-за необходимости передачи контекста (this). Твое решение с лямбдой эту проблему не решает. Можешь подсказать, возможно ли передать контекст в этом API?
0
StailGot
28 / 23 / 6
Регистрация: 25.08.2013
Сообщений: 41
20.07.2014, 00:43 #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 );
2
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
20.07.2014, 01:18 #7
Цитата Сообщение от StailGot Посмотреть сообщение
где последним передается пользовательский параметр, LPARAM dwInitParam, в который передается при первом же вызове callbac'a
А как быть с последующими вызовами? Если, например, на событие WM_CLOSE захочется вызвать какой-то метод класса? Собственно именно поэтому я и не стал предлагать автору решение через этот параметр (естественно я посмотрел MSDN прежде чем спрашивать тебя). Или, все-таки, я чего-то недопонял?
0
StailGot
28 / 23 / 6
Регистрация: 25.08.2013
Сообщений: 41
20.07.2014, 01:32 #8
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
20.07.2014, 03:20 #9
Цитата Сообщение от StailGot Посмотреть сообщение
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
К сожалению это решение с большим количеством недостатков. Ну да ладно, пусть автор решает подойдет ему или нет.
0
Kastaneda
Jesus loves me
Эксперт С++
4689 / 2893 / 236
Регистрация: 12.12.2009
Сообщений: 7,356
Записей в блоге: 2
Завершенные тесты: 1
20.07.2014, 11:49  [ТС] #10
Спасибо за ответы. Да, моя цель была в том, чтобы протащить this в процедуру. С новыми фишками С++11 плотно не работал, поэтому и сделал такую глупость.
Ладно, раз по человечески это сделать не получится, тогда буду строгать костыль пойду обходным путем

Добавлено через 4 минуты
StailGot, спасибо за пример, я с WinAPI тоже не много работал, поэтому не знал такого.
Цитата Сообщение от StailGot Посмотреть сообщение
Создать static переменную в callbac'e, куда и сохранить указатель на класс при первом вызове.
Думаю логичней всего будет сделать статичный vector<pair<HWND, dialog&>>, куда в процедуре при первом вызове сохранять this, привязанный к хенделу диалога. Таким образом можно будет получить нужный this в любое время.
0
Убежденный
Ушел с форума
Эксперт С++
15701 / 7211 / 1139
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 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
Kastaneda
Jesus loves me
Эксперт С++
4689 / 2893 / 236
Регистрация: 12.12.2009
Сообщений: 7,356
Записей в блоге: 2
Завершенные тесты: 1
20.07.2014, 12:20  [ТС] #12
Убежденный, спасибо, я как раз писать сел)
0
20.07.2014, 12:20
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.07.2014, 12:20
Привет! Вот еще темы с ответами:

Вопрос по std::map - C++
В качестве хэш-таблицы для строк (AnsiString) я использовал std::map. От таблицы мне нужно было ещё и такое свойство: я хотел иметь...

Немного про std::string - C++
Привет, читал про std::string на разных сайтах. 1. Там говорят, С++ 11 гарантирует, что std::string будет stored contiguously in...

Создание объекта std::set - C++
http://www.cplusplus.com/reference/stl/set/set/ Вот официальный сайт, по-моему. И вот там такие конструкторы: explicit set ( const...

Файловый поток и std::string - C++
добрый день сейчас меня немножко ввело в тупняк - из файлового потока(ifstream) нельзя прочитать по словам типа std::string? только char*...


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

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Опции темы

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