Search code examples
c++lambdacurrying

Simplest case of currying with a lambda is illegal


The textbook functional programming introduction example "return a function with a curried parameter" in C++ does not compile for me:

// return a function x(v) parameterized with b, which tells if v > b
bool (*greater(int))(int b) 
{
    return [b](int v) { return v > b; };
}

It says that identifier b in the capture [b] is undefined. I know that I'm being naive here, but where is my error?

EDIT: as @some-programmer-dude pointed out correctly, the function signature is wrong.

greater is a function accepting an int b returning ( a pointer * to a function accepting an (int) returning a bool ).

// return a function x(v) parameterized with b, which tells if v > b
bool (*greater(int b))(int) 
{
    return [b](int v) { return v > b; };
}

This of course does not remove the original question which all three replies answered correctly.


Solution

  • You say that greater is a function taking an unnamed (anonymous) int argument, and return a pointer to a function taking an int argument with the name b.

    The part (int b) is the argument list for the returned function pointer.

    To solve that specific problem use

    bool (*greater(int b))(int)
    

    instead.

    Because function pointers are so complicated, they are usually hidden behind type-aliases:

    using greater_function_type = bool(int);
    greater_function_type* greater(int b) { ... }
    

    As for the problem that lambdas with captures can't be used as C-style function pointers, use std::function as return type instead:

    using greater_function_type = std::function<bool(int)>;
    greater_function_type greater(int b) { ... }
    

    Note that it's not returning a pointer anymore.

    Since the C++14 standard you can use automatic return-type deduction with the keyword auto:

    auto greater(int b) { ... }
    

    If you need to store the returned objects, for example as a class member variable, you need to use std::function<bool(int)> for that.


    Also be careful when using names like greater in conjunction with using namespace std; (which is a bad habit), because of std::greater.