According to my understanding, the following program should obviously print:
1.0 hello world 42
However, it fails to compile. Why?
#include <iostream>
#include <string>
using namespace std;
template<class... InitialArgTypes>
void CallWithExtraParameter(void (*funcPtr)(InitialArgTypes..., int), InitialArgTypes... initialArgs)
{
(*funcPtr)(initialArgs..., 42);
}
void Callee(double a, string b, int c)
{
cout << a << " " << b << " " << c << endl;
}
int main()
{
CallWithExtraParameter<double, string>(Callee, 1.0, string("hello world"));
}
Compiler output:
prog.cpp: In function 'int main()':
prog.cpp:18:75: error: no matching function for call to 'CallWithExtraParameter(void (&)(double, std::string, int), double, std::string)'
CallWithExtraParameter<double, string>(Callee, 1.0, string("hello world"));
^
prog.cpp:6:6: note: candidate: template<class ... InitialArgTypes> void CallWithExtraParameter(void (*)(InitialArgTypes ..., int), InitialArgTypes ...)
void CallWithExtraParameter(void (*funcPtr)(InitialArgTypes..., int), InitialArgTypes... initialArgs)
^
prog.cpp:6:6: note: template argument deduction/substitution failed:
prog.cpp:18:75: note: mismatched types 'int' and 'double'
CallWithExtraParameter<double, string>(Callee, 1.0, string("hello world"));
^
There are two main issues with function pointers: Function pointer casts can cause function pointer calls to fail. This may be related to a function pointer cast problem as implicit declarations may have a different type than how you call them.
Pass-by-pointer means to pass a pointer argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the variable to which the pointer argument points. When you use pass-by-pointer, a copy of the pointer is passed to the function.
Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.
A function pointer is a pointer variable, but it holds the address of a function, not the address of a data item. The only things you can do with a function pointer are read its value, assign its value, or call the function that it points toward.
First, "hello world"
wouldn't deduce to std::string
, it would deduce to const char*
, which doesn't match Callee
, so let's fix your call to be pass "hello world"s
instead.
Second, there appears to be some issue with having an argument of type:
void (*funcPtr)(InitialArgTypes..., int)
That is apparently in some limbo between non-deduced context and deducible - in that it's not a non-deduced context (otherwise InitialArgTypes...
would've been deduced from the other parameters) and it's not deducible (because it still failed). So let's go one step further and definitively make it a non-deduced context:
template <class T> struct identity { using type = T; };
template <class T> using identity_t = typename identity<T>::type;
template <class... InitialArgTypes>
void CallWithExtraParameter(void (*funcPtr)(identity_t<InitialArgTypes>..., int),
InitialArgTypes... initialArgs)
{
(*funcPtr)(initialArgs..., 42);
}
Now, InitialArgTypes...
will be deduced from the arguments passed in at the end. Which is what we want, so this works:
CallWithExtraParameter(Callee, 1.0, "hello world"s);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With