Reputation: 615
I have functions Mult, Add, Div, Sub, Mod
those takes two integers and returns the result of its parameters. And a function Calc
that takes a character as an Operator
and returns a pointer to function that returns an integer and takes two integer parameters like Mult
.
Mult
's second parameter is default
So when I call Calc
, Calc
returns the address of Mult
or Add
... depending on the value of parameter of Calc
thus I can pass only one argument. But It doesn't work with pointer to function:
int Add(int x, int y = 2) { // y is default
return x + y;
}
int Mult(int x, int y = 2) { // y is default
return x * y;
}
int Div(int x, int y = 2) { // y is default
return y ? x / y : -1;
}
int Sub(int x, int y = 2) { // y is default
return x - y;
}
int Mod(int x, int y = 2) { // y is default
return y ? x % y : -1;
}
using pFn = int(*)(int, int);
pFn Calc(char c) {
switch (c) {
case '+':
return Add;
case '*':
return Mult;
case '/':
return Div;
case '-':
return Sub;
case '%':
return Mod;
}
return Mult;
}
int main(int argc, char* argv[]){
pFn func = Calc('%');
cout << func(7, 4) << endl; // ok
//cout << func(7) << endl; // error: Too few arguments
cout << Mult(4) << endl; // ok. the second argument is default
func = Calc('/'); // ok
cout << func(75, 12) << endl; // ok
std::cout << std::endl;
}
Above if I call Mult
with a single argument it works fine because the second argument is default but calling it through the pointer func
it fails. func is pointer to function that takes two integers and returns an int.
Upvotes: 18
Views: 2534
Reputation: 18809
If you always have 2
as default argument, you can wrap your function pointer into a simple helper class like this:
using pFn_ = int(*)(int, int);
class pFn
{
pFn_ ptr;
public:
pFn(pFn_ p) : ptr(p) {}
int operator()(int x, int y = 2) const {
return ptr(x,y);
}
};
Full working example: https://godbolt.org/z/5r7tZ8
Upvotes: 2
Reputation: 122133
For the "why not" I refer you to this answer. If you want to somehow keep the ability to use a default, you need to provide something more than a function pointer, eg a lamdba will do:
auto Double() {
return [](int x,int y=2){ return Mult(x,y); };
}
And by using a variadic lambda (thanks to @Artyer) you do not even have to repeat the default value:
#include <iostream>
int Mult(int x, int y = 2) { // y is default
return x * y;
}
auto Double() {
return [](auto... args) { return Mult(args...); };
}
int main(int argc, char* argv[]){
auto func = Double();
std::cout << func(7, 4) << '\n'; // ok
std::cout << func(7) << '\n'; // ok
std::cout << Mult(4) << '\n'; // ok
}
Upvotes: 9
Reputation: 155353
Defaulted arguments are a bit of C++ syntactic sugar; when calling the function directly with insufficient arguments, the compiler inserts the default as if the caller had passed it explicitly, so the function is still called with the full complement of arguments (Mult(4)
is compiled into the same code as Mult(4, 2)
in this case).
The default isn't actually part of the function type though, so you can't use the default for an indirect call; the syntactic sugar breaks down there, since as soon as you are calling through a pointer, the information about the defaults is lost.
Upvotes: 27