# How to call a function with default parameter through a pointer to function that is the return of another function?

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`.

• Functions like `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 '+':
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.

• What is the point of `Double` taking an integer parameter that it doesn't use? – scohe001 Apr 16 at 20:23
• – TrebledJ Apr 16 at 20:23
• @scohe001: In a real example, for example depending on the value of the parameter of `Double` the function returns a pointer to a function from multiple choices: e.g: `switch(x){ case 1: return Mult; break; case 2: return Add;}`. – Syfu_H Apr 16 at 23:08
• @Syfu_H But not the type. I don't know C++ very well, but `using pFn = int(*)(int, int = 2);` or something like that might work. – glglgl Apr 18 at 19:44
• @Syfu_H Ah, ok. Didn't know that, thank you. – glglgl Apr 19 at 6:57

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.

• Thank you! I do really appreciate it. Also: I've edited the question. You can edit it. Now I make the function `Calc` decides which function to return depending on the Character argument passed in to `Calc`. – Syfu_H Apr 16 at 23:32
• @Syfu_H please dont change the quesiton substantially after you got answers. This was an excellent answer for the original question and actually I think it still is – formerlyknownas_463035818 Apr 17 at 8:22

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
}
``````

Live demo

• Note that this involves repeating the default explicitly inside `Double` when defining the `lambda`, which limits the utility significantly. – ShadowRanger Apr 16 at 20:41
• @ShadowRanger yes, added a note – formerlyknownas_463035818 Apr 16 at 20:45
• To not have to repeat the defaults, just forward variadic arguments: `return [](auto... args) { return Mult(args...); }` . Or with perfect forwarding (Which is not really necessary here because this just copies `int`s, but may be for other functions) `return [](auto&&... args) noexcept(noexcept(Mult(std::forward<decltype(args)>(args)...))) -> decltype(auto) { return Mult(std::forward<decltype(args)>(args)...); };` – Artyer Apr 16 at 20:49
• @Artyer thanks. didnt post the forwarding one, because I would have to understand it first myself and for `int`s its not really worth the trouble – formerlyknownas_463035818 Apr 16 at 20:57

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