Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a function pointer from an array of function pointers as a template argument

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]> }.

like image 694
Matti Avatar asked Jan 17 '20 13:01

Matti


People also ask

Can we pass array of pointers to function?

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.

Can a pointer be used as a function argument?

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.

What is the advantage of Replaceing function pointers Withh functors?

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.


1 Answers

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

like image 156
NutCracker Avatar answered Oct 19 '22 00:10

NutCracker