I am trying to use a function with a default argument as a function pointer template parameter:
template <void (*F)()>
class A {};
void foo1(int a = 0) {}
void foo2() {}
int main()
{
//A<foo1> a1; <-- doesn't work
A<foo2> a2;
}
The compiler error is:
main.cpp:7:7: error: could not convert template argument ‘foo1’ to ‘void (*)()’
Is there specific syntax for this to work? Or a specific language limitation? Otherwise, the alternative is to have two separate functions instead of a default parameter:
void foo1(int a) {}
void foo1() { foo1(0); }
Update I understand that the signatures are different, but I'm wondering if there is a way to make this work conveniently without needing to modify all the functions with default parameters?
According to section 8.3.6 of the C++ standard,
Since
A<foo1>
is not a call of the function, default arguments are ignored. In fact, they are ignored in all contexts except the calls of the function, for examplewill not compile, and produce the same message that you get when trying to use
foo1
as a template parameter:This makes sense, because evaluating default arguments is a separate step in the invocation:
The presence of default arguments does not alter the signature of your function. For example, you cannot use a single-argument function with a default argument to override a no-argument virtual member function.
It won't compile because
foo1
has signature:which you're trying to stick into a pointer to:
The function signatures don't match. The fact that
foo1
has a default parameter doesn't change the function's signature (it still can take in anint
).A More Generic Solution
I'd say forget about the templates, they're only limiting you here.
Personally, the way I solve the callback problem is using function objects with argument binding. It can be done using the boost::function library, and binding default arguments with boost::bind (or
std::bind1st
andstd::bind2nd
).These boost libraries are also built-in to the new C++11 standard, as
std::function
, andstd::bind
.It's well worth taking a look at this, as it let's you do some very nice things, like providing default arguments to functions, or use class member functions as callbacks.
The sites I've linked to all have lots of example code, and the boost links have tutorials.
Default argument values are not part of the function type. You can't use
foo1
as a function taking no arguments, because it does take one argument. The argument gets filled in for you if you don't mention it, but it's still there.Your workaround involving a dispatching function sounds like a good solution. It could even be templated if you need it a lot.
The signature of
foo1
isvoid(int)
, notvoid()
. This is why it isn't convertible tovoid(*)()
.You are confusing default arguments with overloading.
I'm pretty sure that a function pointer has signature of the function with all default parameters expanded and function pointers cannot convert to a function pointer with a different signature. Finding this in the standard is a different matter, though...
I think the relevant clause from the standard is 8.3.5 [dcl.fct] paragraph 6:
Note that default arguments are the guys of the form
= value
according to 8.3.6 [dcl.fct.default] paragraph 1: