0

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?

4
  • 1
    what errors does it give? Commented May 18, 2020 at 14:56
  • Such things are usually made with template, then it will be much more flexible. Another alrternative is std::function but it has overhead. Function pointer is the least flexible IMHO. It is unrelated to your error though, and your problem is unrelated to function pointer Commented May 18, 2020 at 15:01
  • 1
    you cant skip parameters or change the order of the signature or give more parameters, the compiler can't know that the variable that you send to the function is the forth param and not the third Commented May 18, 2020 at 15:04
  • 1
    Based on the context of the question I think bool pbar = bar(bt, vs); should be bool (*pbar)(bool, void*) = bar; Commented May 18, 2020 at 15:11

4 Answers 4

3
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)

Sign up to request clarification or add additional context in comments.

2 Comments

It looks like OP intended pbar to be a function pointer, but in their example it is just a bool. But that still just works because it implicitly converts to int.
whatever shenanigans and luck made OPs code make sense somewhat, i don't believe he understood how the parameters worked anyways. this should help him fix his code.
2

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

Comments

2

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.

Comments

1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.