Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function overload using lambda function signature

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.

like image 266
Haatschii Avatar asked Jan 03 '15 00:01

Haatschii


People also ask

What would the signature in function overloading function?

Function Signature A function's signature includes the function's name and the number, order and type of its formal parameters. Two overloaded functions must not have the same signature. The return value is not part of a function's signature.

Can lambda functions be overloaded?

No, you can not overload the lambda! Which is not possible, as the same variable name can not be reused in C++.

What is the correct syntax for Lambda Expression in C++11?

Lambdas can both capture variables and accept input parameters. A parameter list (lambda declarator in the Standard syntax) is optional and in most aspects resembles the parameter list for a function. auto y = [] (int first, int second) { return first + second; };

How do you write a Lambda function in C++?

Creating a Lambda Expression in C++auto greet = []() { // lambda function body }; Here, [] is called the lambda introducer which denotes the start of the lambda expression. () is called the parameter list which is similar to the () operator of a normal function.


2 Answers

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;}));
like image 124
Brian Bi Avatar answered Sep 28 '22 12:09

Brian Bi


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.

like image 28
rparolin Avatar answered Sep 28 '22 14:09

rparolin