Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function with default arguments as an argument

So, I know that you can pass a function as an argument like so:

int a(int x) {
    return x + 1;
}

int b(int (*f)(int), int x) {
    return f(x); // returns x + 1
}

I also know you can have a function with default arguments, like so:

int a(int x = 1) {
    return x;
}

a(2); // 2
a();  // 1

However, how do I pass a function with default arguments to a function and preserve this behavior?

I've tried the following:

int b(int (*f)(int), int x) {
    f(x); // works as expected
    f();  // doesn't work because there aren't enough arguments to f
}

and

int b(int (*f)()) {
    f();  // doesn't work because it cannot convert int (*)(int) to int (*)()
}
like image 949
hyper-neutrino Avatar asked Dec 08 '21 21:12

hyper-neutrino


1 Answers

There is no way to forward default parameter values with function pointers.

But you can make it work if you can turn b into a templated function:

By using a parameter pack for operator() and explicitly calling a we give the compiler the opportunity to apply the default argument values if needed:

int a(int x = 12) {
    return x + 1;
}

template<class T>
int b(T f, int x) {
    return f() + f(x);
}

struct AFnWrapper {
    template<class... Args>
    auto operator()(Args&&... args) {
        return a(std::forward<Args>(args)...);
    }
};

int main() {
   std::cout << b(AFnWrapper{}, 1) << std::endl; // 15
}

A shorter version of this would be to just use a lambda:

std::cout << b([](auto&&... args) { return a(std::forward<decltype(args)>(args)...); }, 1) << std::endl;

If you don't need perfect forwarding you can make it even shorter:

std::cout << b([](auto... args) { return a(args...); }, 1) << std::endl;

godbolt example

like image 119
Turtlefight Avatar answered Sep 17 '22 12:09

Turtlefight