12

Consider the following example

void foo(const std::function<int()>& f) {
    std::cout << f() << std::endl;
}

void foo(const std::function<int(int x)>& f) {
std::cout << f(5) << std::endl;
}

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

    foo([](int x){return x;});
}

This does not compile, because the call to foo is said to be ambiguous. As far as I understand this is due to the fact, that the lambda function is not a priori a std::function but has to be casted to it and that there is a std::function constructor that takes an arbitrary argument.

Maybe someone can explain to me why anyone would create an implicit constructor that takes an arbitrary argument. However my acutual question is whether there is a workaround, which allows to use the function signature of lambda functions to overload a the function foo. I have tried function pointers, but that didn't work because capturing lambda functions can't be cast to a normal function pointer.

Any help is most welcome.

8
  • 7
    This is probably a bug in MSVC. It works in Clang/GCC. Commented Jan 3, 2015 at 0:15
  • 3
    Oh Microsoft, you so funny Commented Jan 3, 2015 at 0:17
  • 1
    @remyabel & Mohammad I believe Mr. Microsoft deserves an apology here. That is not a nice way to behave! Commented Jan 3, 2015 at 0:33
  • 2
    Sorry Mr. Microsoft. ;_; Commented Jan 3, 2015 at 0:33
  • 1
    Ok, thanks everyone. I tested it with GCC 4.8 and in fact it worked. So I'll probably have to upgrade my GCC. Commented Jan 3, 2015 at 0:46

2 Answers 2

16

Your compiler is correct according to C++11. In C++14, a rule is added that says that the constructor template shall not participate in overload resolution unless the type of the argument is actually callable with the std::function's argument types. Therefore, this code is supposed to compile in C++14, but not in C++11. Consider this to be an oversight in C++11.

For now, you can work around this by explicit conversion:

foo(std::function<int()>([](){return 3;}));
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for clarification. Following the comments I tried it using GCC 4.8 (and -std=c++11) and it worked. Somehow funny that the newer version of GCC therefore does not use strictly correct c++11.
@Haatschii It's a defect in the C++11 standard; the compiler/library devs usually apply fixes retroactively. (Besides, it was UB in C++11 anyway, so having the C++14 behavior is permissible.)
8

http://coliru.stacked-crooked.com/a/26bd4c7e9b88bbd0

An alternative to using std::function is to use templates. Templates avoid the memory allocation overhead associated with std::function. The template type deduction machinery will deduce the correct type of the lambda passed so the call site cast goes away. However you still have is disambiguate the overloads for the no-args vs args case.

You can do this using a trick with trailing return types that behave similar to enable_if.

template<typename Callable>
auto baz(Callable c) 
    -> decltype(c(5), void())
{
    std::cout << c(5) << std::endl;
}

The above overload of baz will only be a valid overload candidate when the template parameter Callable can be called with an argument of 5.

You can put more advanced mechanisms on top of this to make it more general (ie. variadic pack expansion of args into callable) but I wanted to show the basic mechanism working.

2 Comments

#include <functional> seems to be missed in your example on coliru.
Please tell how does decltype(c(5), void()) works or where to read? As far as I understand c(5) is only to say we expect Callable c accepts 1 argument of type int, then operator, and real return type, more accurately "construct" value of type void to be used as an argument to decltype. So the trick is to restrict Callable to be callable with some args and then return void. Right?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.