1
#include <functional>

void foo(std::function<void()> f) { f(); }
void foo(void (*f)()) { f(); }

int main ()
{
  foo( [](){} );
}

VS compiles, gcc and clang complain about ambiguous overload. Who's right? The lambda is supposed to be of a class type, so there should not be any conversion between it and a function pointer. Thus VS appears to be right, against all odds. But perhaps I'm missing something.

Is there a simple way to disambiguate the call, apart from casting the lambda to either type?

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243

2 Answers2

4

A lambda creates an anonymous and unspecified object that can be called, it's neither a function pointer nor a std::function object but can be used as both a function pointer and a std::function object, giving you the ambiguous overload error. I would say that VS is wrong.

Also, since a function pointer can be used to create a std::function object, I would say that using an overload that takes a function pointer is not needed if you already have a function taking a std::function argument.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 1
    The standard says: *The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed nonunion _class type_*. The function pointer overload is more efficient as `std::function` involves all kinds of overhead (not significant in my particular case, but on principle I should not be forced to pay this cost). – n. m. could be an AI Jul 21 '13 at 11:40
  • @n.m - Whether it's a class type or not bears no relevance here - conversions between class types and between a class type and a builtin type are equal in the eyes of the overload resolution algorithm. Adding a special case just for the sake of lambdas would be a needless complication. – JohannesD Jul 21 '13 at 12:51
  • @JohannesD - *Why* is there a conversion between this particular class type and the function pointer type? Does the standard explicitly mention such a conversion? – n. m. could be an AI Jul 21 '13 at 13:11
  • @n.m. - Because it's useful. The standard specifies this in 5.1.2/6: *The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.* – JohannesD Jul 21 '13 at 13:17
3

Non-capturing lambdas have an implicit conversion to a function pointer with the same signature. This is specified in chapter 5.1.2 paragraph 6:

The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

JohannesD
  • 13,802
  • 1
  • 38
  • 30