zyydoosh
zyydoosh

Reputation: 379

How to make a recursive lambda function that takes 2 arguments not 1?

I already know how to make a recursive lambda function that take one argument like calculating factorial of a number, but I try to make a recursive power function using lambda (as a practice), but taking 2 arguments in the function caused errors

this the code :

std::function <int(int)> power = [&](int a, int n)
{
    return (n<=1) ? a : a*power(a, n-1);
};

this line return (n<=1) ? a : a*power(a, n-1); gives these errors :

error:   no match for call to '(std::function<int(int)>) (int&, int)'
note:   candidate: _Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = int; _ArgTypes = {int}]
note:   candidate expects 1 argument, 2 provided

Upvotes: 1

Views: 181

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275966

Your recursive lambda runs into a problem; it requires the exact variabke it was created in to exist, or it is UB to call it.

auto ycomb = [](auto&&f){ return [f=f](auto&&...args){ return f(f, decltype(args)(args)...); }; };

this little toy fixes that bug.

auto power = ycomb( [](auto&& self, int a, unsigned int n)->int
{
  return (n==0) ? 1 : a*self(self, a, n-1);
});

there.

ycomb is the ycombinator. It is famous.

This power can be copied around and can outlive the scope of its construction safely.

If you don't like self(self, args...) you can reuse ycombinator to make it:

auto ycomb0 = [](auto&&f){
  return [=](auto&&...args){
    return f(f, decltype(args)(args)...);
  };
};
auto ycombx_ref = [](auto&& r, auto&& f) {
    return [&r, f](auto&&...args) {
        return f( r(r, f), decltype(args)(args)... );
    };
};
auto ycomb = ycomb0( ycombx_ref );

and now the self passed to the lambda doesn't itself need to be passed self:

auto power = ycomb( [](auto&& self, int a, unsigned int n)->int
{
  return (n==0) ? 1 : a*self(a, n-1);
});

Live example.

Upvotes: 0

R Sahu
R Sahu

Reputation: 206747

You'll have to use

std::function <int(int, int)> power = [&](int a, int n) { ... }

for the function to work with two arguments.

Suggestions for improment:

Make sure you deal with n = 0 correctly.

Use of

return (n <= 1) ? a : a*power(a, n-1);

is not right. You will get back a when the function is called with n = 0.

Use

return (n == 0) ? 1 : a*power(a, n-1);

Use unsigned int for n.

std::function <int(int, unsigned int)> power = [&](int a, unsigned int n) { ... }

Then, you won't have to worry about the function getting called with negative values for n.


Complete function

std::function <int(int, unsigned int)> power = [&](int a, unsigned int n)
{
    return (n == 0) ? 1 : a*power(a, n-1);
};

Upvotes: 4

max66
max66

Reputation: 66230

Maybe

std::function <int(int, int)> power = [&](int a, int n) ....
// ...................^^^^^

?

I mean: if power is a std::function that is initialized with a lambda that receive two integers, and is uses as a functional that receive two integers, maybe is the case to declare it as receiving two integers, not only one.

Upvotes: 4

Related Questions