AngusTheMan
AngusTheMan

Reputation: 582

Default parameter and function pointer as function arguments C++

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

Answers (4)

Pete Becker
Pete Becker

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

BubLblckZ
BubLblckZ

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

eerorika
eerorika

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

tb044491
tb044491

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

Related Questions