Reputation: 582
I have a function which takes arguments, default arguments and finally, a pointer to another function and a void pointer.
As an example, consider the following
int foo(double arg 1, bool arg 2, int arg3=0, int arg4=2, bool (*pbar)(bool,void*), void* data=0);
It is called in several places across my codebase. I have noticed that when the function pointer itself has arguments, then the default arguments, it is required that the default parameters must also be specified, even if the value I desire is the default one. For instance, the following code will compile
foo(arg1, arg2, pbar);
But the below snippet will not
foo(arg1, arg2, pbar, (void*) myint);
As a more complete example, here is a working snippet.
#include <iostream>
using namespace std;
int foo(double arg1, bool arg2, int arg3=0, int arg4=2, bool (*pbar)(bool,void*)=0, void* data=0)
{
return 1;
}
bool bar(bool bt, void* vs)
{
return false;
}
int main()
{
double arg1 = 0.0;
bool arg2 = false;
bool bt = true;
int i = 1;
void* vs = &i;
bool pbar = bar(bt, vs);
// no defaults specified and no function pointer arguments
foo(arg1, arg2, pbar);
// specify one of the defaults
int arg3 = 23;
foo(arg1, arg2, arg3, pbar);
// don't specify the defaults, but give arguments to function pointer
//foo(arg1, arg2, pbar, bt, vs);
return 0;
}
The final commented call will not compile.
So my question is, why upon the specification of the function pointer arguments does this fail to compile?
I have already found a solution to the problem by using the 'named parameter' method. Whereby I create a class and instantiate members with references. However, I am interested in an in-depth explanation as to why the above fails.
The error is presented below
main.cpp: In function ‘int main()’:
main.cpp:41:33: error: invalid conversion from ‘void*’ to ‘bool (*)(bool, void*)’ [-fpermissive]
foo(arg1, arg2, pbar, bt, vs);
^
main.cpp:13:5: note: initializing argument 5 of ‘int foo(double, bool, int, int, bool (*)(bool, void*), void*)’
int foo(double arg1, bool arg2, int arg3=0, int arg4=2, bool (*pbar)(bool,void*)=0, void* data=0)
^~~
I believe this is because the order of the parameters is messed up. However, why can I insert the function pointer and not worry about the default arg3 and arg4?
Upvotes: 0
Views: 448
Reputation: 76245
The fundamental principle behind default arguments is that they apply to the right-most arguments in the argument list.
void f(int, double = 0, void* = 0); // okay
void g(int, double = 0, void*); // error: third argument needs a default value
Similarly, when calling a function with default arguments, only the rightmost arguments get their default values:
f(3); // okay; second and third arguments get default values
f(3, 1.0); // okay; third argument gets default value
int x;
f(3, 1.0, &x); // okay; no default arguments used
You can't skip arguments, even if it's possible to determine which one you meant:
f(3, &x); // illegal: second argument has type double, and &x can't be converted to double
This can get confusing if one of the arguments is convertible to the appropriate type, and it looks like that might be what's happening in the code in the question that compiles. For example,
void h(int, bool = false, int* = 0);
int x;
h(3, &x); // okay; &x gets converted to bool
h(3, true); // same as the previous one
h(3, false, &x); // okay, all three arguments provided
Upvotes: 1
Reputation: 463
The arguments still have to be in the right order. Then you can choose how many of the optional arguments you want to include, but note that you can't skip any optional arguments.
So in your case, foo(arg1, arg2, pbar) works because pbar isn't a function, it's just a boolean. bar() returns false so pbar is going to be set to 0, which is then casted to an integer when doing foo(arg1, arg2, pbar) because the third argument is an integer, so that's why it works.
Same thing with the second call, foo(arg1, arg2, arg3, pbar), pbar is still just 0.
The commented call returns an error because as mentioned, you can't skip over optional arguments, so foo(arg1, arg2, pbar, bt, vs) will pass in vs, a void pointer, as a function pointer. If there is a specific optional argument you want to include, you will have to specify all the arguments before that one.
Upvotes: 2
Reputation: 238311
So my question is, why upon the specification of the function pointer arguments does this fail to compile?
It fails to compile beause the argument that you pass has the wrong type. The type of the parameter is a pointer to function. You are passing a void*
instead, which is an object pointer. void*
is not implicitly convertible to pointer to function.
int foo( double arg1, bool arg2, int arg3=0, int arg4=2, bool (*pbar)(bool,void*)=0, void* data=0) 1 2 3 4 ^^^^^^^^^ 5 ^^^^^^^^^^^^ pointer to function void* vs = &i; ^^^^^ not a pointer to function foo(arg1, arg2, pbar, bt, vs); 1 2 3 4 ^5
Upvotes: 2
Reputation: 144
int foo(double arg1, bool arg2, int arg3 = 0, int arg4 = 2, bool * pbar(bool , void *) = 0, void * data = 0);
the compiler only cares about the order of the parameters.
you cannot skip defining arg3 and arg4 because they have default values.
by doing this:
foo(arg1, arg2, pbar);
you are basically passing "pbar" (which is a function) where "arg3" is supposed to be (which is an integer)
Upvotes: 3