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 (*)()
}
CodePudding user response:
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;
CodePudding user response:
It's not possible to do this with function pointers, as function pointers don't have the ability to store information about default arguments. However, you can pass around a function object that happens to have a member function with default arguments.
Converting a
to such an object is straightforward; just make it a lambda
auto a = [](int x = 1) {
// ...
};
and then b
can take a function object, where the type is deduced
template<typename F>
int b(F f, int x) {
f(x); // ok
f(); // also ok, default value is 1
}
Here's a demo.