Passer un pointeur de fonction à partir d'un tableau de pointeurs de fonction comme argument de modèle

9

Je voudrais passer un pointeur de fonction à partir d'un tableau de pointeurs de fonction comme argument de modèle. Mon code semble se compiler en utilisant MSVC même si Intellisense se plaint que quelque chose ne va pas. Gcc et clang ne parviennent pas à compiler le code.

Prenons l'exemple suivant:

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 compile le code mais Intellisense donne l'erreur suivante:invalid nontype template argument of type "const FunctionPointer"

gcc ne parvient pas à compiler avec le message suivant:

<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 ne parvient pas à compiler avec le message suivant:

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

Des questions:

Est wrapper_function<functions[0]>();valide ou non?

Si ce n'est pas le cas, puis-je faire quelque chose pour passer functions[0]comme argument de modèle wrapper_function? Mon objectif est de construire un nouveau tableau de pointeurs de fonction au moment de la compilation, avec le contenu { wrapper_function<functions[0]>, ..., wrapper_function<functions[std::size(functions) - 1]> }.

Matti
la source
Hmm c'est intéressant, je pensais que le problème était que vous utilisiez une valeur (un pointeur) au lieu d'un type. Mais même wrapper_function<decltype(functions[0])>()ne compile pas.
CoryKramer
6
Semble fonctionner en C ++ 17 ... maintenant pour trouver la différence en standard ...
AndyG

Réponses:

5

L'expression wrapper_function<functions[0]>();est interdite pour les raisons suivantes:

14.3.2 Arguments de non-type de modèle [temp.arg.nontype]

Un argument de modèle pour un paramètre de modèle non type et non modèle doit être l'un des éléments suivants:

[...]

- une expression constante (5.19) qui désigne l'adresse d'un objet avec stockage statique> durée et liaison externe ou interne ou une fonction avec liaison externe ou interne, y compris les modèles de fonction et les identifiants de modèle de fonction mais à l'exclusion des membres de classe non statiques, exprimés (en ignorant les parenthèses) en tant qu'expression & id, sauf que le & peut être omis si le nom fait référence à une fonction ou à un tableau et doit être omis si le paramètre-modèle correspondant est une référence; [...]

Il est interdit d'utiliser des pointeurs comme arguments de modèle non-type autres que ceux du formulaire, &iddonc, fondamentalement, cela fonctionnerait:

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
}

et l'extrait suivant ne fonctionnera pas lorsqu'il est compilé avec l'option C ++ 14:

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

Une fois compilé avec l'option C ++ 17, votre approche et celle ci-dessus fonctionneraient toutes les deux:

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

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

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

Voir en direct

Casse Noisette
la source
Non seulement le formulaire &id, mais idest également autorisé pour les fonctions, comme vous le démontrez dans l'exemple et une valeur de pointeur null est explicitement autorisée sous forme d'expression constante.
noyer
C ++ 17 remplace cela par une " expression constante convertie ", c'est-à-dire qu'il permet de chaîner des expressions constantes donc wrapper_function<func>()cela fonctionnera également.
rustyx
Ok vérifiera et mettra à jour la réponse après l'avoir écrite en entier. Tnx
NutCracker