Passando un puntatore a funzione da una matrice di puntatori a funzione come argomento modello


9

Vorrei passare un puntatore a funzione da una matrice di puntatori a funzione come argomento modello. Il mio codice sembra compilarsi usando MSVC anche se Intellisense si lamenta che qualcosa non va. Sia gcc che clang non riescono a compilare il codice.

Considera il seguente esempio:

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 compila il codice ma Intellisense dà il seguente errore:invalid nontype template argument of type "const FunctionPointer"

gcc non riesce a compilare con il seguente messaggio:

<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 non riesce a compilare con il seguente messaggio:

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

Domande:

È wrapper_function<functions[0]>();valido o no?

In caso contrario, c'è qualcosa che posso fare per passare functions[0]come argomento modello wrapper_function? Il mio obiettivo è quello di costruire un nuovo array di puntatori a funzione al momento della compilazione, con il contenuto { wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }.


Hmm questo è interessante, ho pensato che il problema fosse che stavi usando un valore (un puntatore) invece di un tipo. Ma anche wrapper_function<decltype(functions[0])>()non compilare.
CoryKramer il

6
Sembra funzionare in C ++ 17 ... ora per trovare la differenza in standardese ...
AndyG

Risposte:


5

L'espressione wrapper_function<functions[0]>();è vietata a causa di quanto segue:

14.3.2 Argomenti non di tipo template [temp.arg.nontype]

Un argomento modello per un parametro modello non tipo e non modello deve essere uno dei seguenti:

[...]

- un'espressione costante (5.19) che designa l'indirizzo di un oggetto con memoria statica> durata e collegamento esterno o interno o una funzione con collegamento esterno o interno, inclusi modelli di funzione e ID modello di funzione ma esclusi membri di classe non statici, espresso (ignorando le parentesi) come & id-expression, tranne per il fatto che & può essere omesso se il nome si riferisce a una funzione o a un array e deve essere omesso se il parametro template corrispondente è un riferimento; [...]

È vietato utilizzare i puntatori come argomenti di modello non di tipo diversi da quelli del modulo &id, quindi, in sostanza, dovrebbe funzionare come segue:

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
}

e il frammento seguente non funzionerà se compilato con l'opzione C ++ 14:

constexpr auto func = &test;
wrapper_function<func>();

Se compilato con l'opzione C ++ 17, il tuo approccio e quello sopra funzionerebbero entrambi:

int main()
{
    test();  // OK
    functions[0]();  // OK

    wrapper_function<test>();  // OK
    wrapper_function<&test>();  // OK
    wrapper_function<func>();  // OK

    wrapper_function<functions[0]>();  // OK
}

Vedi dal vivo


Non solo il modulo &id, ma idè anche consentito per le funzioni, come si sta dimostrando nell'esempio e un valore di puntatore null è esplicitamente consentito in forma di espressione costante.
Noce

C ++ 17 sostituisce quello con una " espressione costante convertita ", ovvero consente di concatenare espressioni costanti e quindi wrapper_function<func>()funziona.
Rustyx,

Ok controlla e aggiorna la risposta dopo averla scritta per intero. TNX
Schiaccianoci
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.