2
static std::function<LRESULT(int nCode, WPARAM wParam, LPARAM lParam)> keyProc =
        [](int nCode, WPARAM wParam, LPARAM lParam)->LRESULT {
        return 1;
    };
    keyHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyProc, theApp.m_hInstance, NULL);

Error C2664 'HHOOK SetWindowsHookExW(int,HOOKPROC,HINSTANCE,DWORD)': cannot convert argument 2 from 'std::function' to 'HOOKPROC' MFCTest d:\test\mfctest2\mfctest\keymaphooker.cpp 62

PS: Why did I use such a long expression rather than auto? Because I want to it be static.

I changed it to

auto keyProc =
        [this](int nCode, WPARAM wParam, LPARAM lParam)->LRESULT {
         return 1;//return KeyboardProc(keyHook, keyMap, nCode, wParam, lParam);
    };

It doesn't work again.

error C2664: 'HHOOK SetWindowsHookExW(int,HOOKPROC,HINSTANCE,DWORD)': cannot convert argument 2 from 'KeyMapHooker::StartHook::' to 'HOOKPROC'

Zhang
  • 3,030
  • 2
  • 14
  • 31

1 Answers1

3

A stateless lambda (such as the one you are using) can indeed be converted to a pointer to function, and thus can be used as CALLBACK. However, std::function cannot be converted in this manner.

Note that the type of a lambda expression is not std::function, it's an unnamed class type (the closure type of the lambda expression). You can capture the correct type using auto (which has no effect on storage duration):

static auto keyProc =
        [](int nCode, WPARAM wParam, LPARAM lParam)->LRESULT {
        return 1;
    };
    keyHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyProc, theApp.m_hInstance, NULL);
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Oh, the new version VS can support static auto. I have tried this previously on the vs2010, it couldn't. Now I use VS2017. I have never tried static auto again. Now, I know, I can just use static auto. – Zhang Jun 08 '18 at 07:42
  • You can also do `SetWindowsHookEx(WH_KEYBOARD_LL, [](int nCode, WPARAM wParam, LPARAM lParam) -> LRESULT { ... }, ...);` – Jonathan Potter Jun 08 '18 at 07:44
  • @JonathanPotter Then the lambda will not be static, of course. – Angew is no longer proud of SO Jun 08 '18 at 07:45
  • Wait!!!! I just tried your code can work. But, When I add a capture: [this](/*others don't change*/)... It doesn't work again. – Zhang Jun 08 '18 at 07:48
  • @马化腾 Of course. As I said (and as the standard says), only *stateless* lambdas (i.e. lambdas which don't capture anything) can be converted to function pointers. – Angew is no longer proud of SO Jun 08 '18 at 07:49
  • @Angew, that makes the lambda be less useful :( – Zhang Jun 08 '18 at 07:51
  • @马化腾 Think about it. How would `this` get passed to `SetWindowsHookEx`? A (non-stateless) lambda is more than just a simple C-style function pointer. – Paul Sanders Jun 08 '18 at 07:52
  • @马化腾 Also, having a static lambda capturing `this` smells like trouble. Is the class a singleton? – Angew is no longer proud of SO Jun 08 '18 at 07:55
  • If you want the usefulness of combining capturing lambdas with the ability to pass it as a function pointer you can use libffi's closure system. It creates (small) chunks of binary at run-time. It's not as convenient syntactically but it enables some very useful idioms. – SoronelHaetir Jun 08 '18 at 15:41