I would like to pass a function pointer from an array of function pointers as a template argument. My code seems to compile using MSVC even though Intellisense complains that something is wrong. Both gcc and clang fail to compile the code.
Consider the following example:
static void test() {}
using FunctionPointer = void(*)();
static constexpr FunctionPointer functions[] = { test };
template <FunctionPointer function>
static void wrapper_function()
{
function();
}
int main()
{
test(); // OK
functions[0](); // OK
wrapper_function<test>(); // OK
wrapper_function<functions[0]>(); // Error?
}
MSVC compiles the code but Intellisense gives the following error: invalid nontype template argument of type "const FunctionPointer"
gcc fails to compile with the following message:
<source>: In function 'int main()':
<source>:19:33: error: no matching function for call to 'wrapper_function<functions[0]>()'
19 | wrapper_function<functions[0]>(); // Error?
| ^
<source>:8:13: note: candidate: 'template<void (* function)()> void wrapper_function()'
8 | static void wrapper_function()
| ^~~~~~~~~~~~~~~~
<source>:8:13: note: template argument deduction/substitution failed:
<source>:19:30: error: '(FunctionPointer)functions[0]' is not a valid template argument for type 'void (*)()'
19 | wrapper_function<functions[0]>(); // Error?
| ~~~~~~~~~~~^
<source>:19:30: note: it must be the address of a function with external linkage
clang fails to compile with the following message:
<source>:19:2: error: no matching function for call to 'wrapper_function'
wrapper_function<functions[0]>(); // Error?
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:8:13: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'function'
static void wrapper_function()
^
1 error generated.
Questions:
Is wrapper_function<functions[0]>();
valid or not?
If it isn't, is there anything I can do to pass functions[0]
as a template argument to wrapper_function
? My goal is to construct a new array of function pointers at compile time, with the content { wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }
.
C++ does not allow to pass an entire array as an argument to a function. However, You can pass a pointer to an array by specifying the array's name without an index.
Pointer as a function parameter is used to hold addresses of arguments passed during function call. This is also known as call by reference. When a function is called by reference any change made to the reference variable will effect the original variable.
You often use functors instead - that is, classes that overload the operator () , so that they can be "called" as if they were functions. Functors have a couple of big advantages over function pointers: They offer more flexibility: they're full-fledged classes, with constructor, destructor and member variables.
Expression wrapper_function<functions[0]>();
is forbidden because of the following:
14.3.2 Template non-type arguments [temp.arg.nontype]
A template-argument for a non-type, non-template template-parameter shall be one of:
[...]
— a constant expression (5.19) that designates the address of an object with static storage > duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; [...]
It is forbidden to use pointers as non-type template arguments other than of the form &id
so, basically, following would work:
static void test() {}
using FunctionPointer = void(*)();
static constexpr FunctionPointer functions[] = { test };
template <FunctionPointer function>
static void wrapper_function()
{
function();
}
int main()
{
test(); // OK
functions[0](); // OK
wrapper_function<test>(); // OK
wrapper_function<&test>(); // OK
}
and following snippet won't work when compiled with C++14 option:
constexpr auto func = &test;
wrapper_function<func>();
When compiled with C++17 option, your approach and the one above would both work:
int main()
{
test(); // OK
functions[0](); // OK
wrapper_function<test>(); // OK
wrapper_function<&test>(); // OK
wrapper_function<func>(); // OK
wrapper_function<functions[0]>(); // OK
}
See live
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