13

I've got a library that I need to use that defines the following:

typedef void CallbackFunction(const int& i);

and has a function to register your callback that looks like:

void registerCallback(CallbackFunction* pCallback);

Because I'd like to capture the state of several variables to be used in the callback, I can't simply use a plain function. What I'd prefer to use is a lambda function, but the following doesn't compile:

auto fCallback = [](const int& i) {
    cout << i << endl;
};
registerCallback(fCallback);

instead I get the error:

error C2664: 'registerCallback' : cannot convert parameter 1 from '`anonymous-namespace'::<lambda0>' to 'CallbackFunction (__cdecl *)'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

I've been reading up on this topic a lot, and trying a few different (probably idiotic) approaches, but I can't seem to get this to work. Casting the function allows the code to compile, but (not surprisingly) it crashes. It may be that I've overlooked the solution either here on StackOverflow or elsewhere, so a link will suffice. (Though, since I'm a bit new to some of these techniques, please make sure that the correspondence is clear enough for a newbie. For instance, if this conversation contains my answer, I don't understand. Please simplify or explain the correspondence.) FYI, I'm using Visual C++ 2010.

Please let me know if there is anything I can do to clarify my question. Thanks in advance for the help!

Community
  • 1
  • 1
Michael Repucci
  • 1,633
  • 2
  • 19
  • 35

4 Answers4

8

In general, no you can't use a lambda or function object where a function pointer is required. Function objects are full-fledged objects that have overloaded the application operator (()) so you can use them as functions syntactically.

The standard algorithms are written as templates, which allows you to pass either a function address (pointer) or a function object to them, because they use the same syntax. When you pass a function object, a template is instantiated which accepts that function object; when you pass a function pointer, a different template is instantiated.

So to get lambdas/function objects to work with your code, you would need to modify the library you're using.

Daniel Gallagher
  • 6,915
  • 25
  • 31
  • 7
    This is actually only partially correct. Lambda expressions, as they will work in C++0x, have an implicit conversion function to function pointer IFF they do not capture any scope. VS2010 does not implement this feature because it came after they released that compiler. – Edward Strange Jan 22 '11 at 07:03
  • @Noah Roberts: Any hint on where this is defined? – Martin York Jan 22 '11 at 07:48
8

Since you capture nothing, you are supposed to be able to do what you're trying to do, namely assign a lambda expression as a function pointer (though your syntax is wrong there).

Since you're using VS2010 though, you won't be able to. The feature of lambda that you're trying to use did not come to be until after VS2010 was released: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3043.html

So while yes, it's supposed to work it in fact does not.

Of course, while you are not, in fact, capturing anything you do state that you want to. Lambdas that capture data cannot be converted to function pointers even in the post VS2010 state of the C++ draft standard.

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
  • Thanks for this info Noah! But yes, I do want to capture data, so you're correct that even if it were implemented in VS2010, this trick wouldn't work for my case. Nevertheless, it's most definitely worth knowing. – Michael Repucci Jan 24 '11 at 15:18
  • 1
    Is the ability to convert a lambda with captures to a function pointer something they could plausibly add to the language? – Fredrick Aug 24 '11 at 19:55
4

Short Answer: No

Long Answer:

Lamda's are just syntactic sugar for functors.
Functors are objects that act like functions.

A function pointer is not the same type of thing. In general you can not use functors where you need a function pointer.

Extra:

On the other hand it is easy to wrap a function to become a functor.

Historically:

Function pointers are generally used by C libraries. As C++ libraries will use an interface to achieve the same affect. Thus you can see why it is hard to pass functors where a function pointer is requried (the C code has no way to understand how to use the functor).

Community
  • 1
  • 1
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 1
    Wrapping a functor in a function requires the callback to pass an arbitrary pointer that can be cast back to the functor. If that capability wasn't provided in the API, you're out of luck. – Mark Ransom Jan 21 '11 at 23:17
0

You can't use lambdas, because your registerCallback function expects pointer to non-member function. The only way to pass additional parameter to free standing function is 1) using global (static) data or 2) making it a template taking compile time constants, e.g.

template<int data> void callback(const int& i)
{ /* can use data */ }

registerCallback(callback<10>);
Gene Bushuyev
  • 5,512
  • 20
  • 19