2 votes

Paramètre de modèle variadique au milieu de la liste de paramètres

J'essaie de spécifier une fonction qui prend une fonction générique comme paramètre. La fonction est définie comme suit :

template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);

Comment spécifier une fonction générique qui prend cette fonction générique comme paramètre ? J'ai essayé ceci :

template<typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
TRet wrap(TsArgs... args) {
  return F(args...);
}

Pour envelopper cette fonction :

bool foo(int x, double y) {
    return x < y;
}

Comme ça :

Fun<bool, int, double> func = wrap<bool, int, double, foo>;

Cependant, cela ne compile malheureusement pas. gcc 8.1 a le message d'erreur suivant :

<source>:16:35: error: no matches converting function 'wrap' to type 'Fun<bool, int, double>' {aka 'bool (*)(int, double)'}
     Fun<bool, int, double> func = wrap<bool, int, double, foo>;
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

et clang 6 a l'erreur suivante :

<source>:16:35: error: address of overloaded function 'wrap' does not match required type 'bool (int, double)'
    Fun<bool, int, double> func = wrap<bool, int, double, foo>;
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

Cependant, si je remplace le TsArgs con int, double comme dans la signature de foo() il se compile très bien, ce qui me laisse penser que les arguments variadiques des modèles au milieu de la liste des paramètres ne fonctionnent pas comme prévu. Comment pourrais-je atteindre mon objectif autrement ?

Voici le MCVE :

template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);

template<typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
TRet wrap(TsArgs... args) {
    return F(args...);
}

bool foo(int x, double y) {
    return x < y;
}

int main() {
    Fun<bool, int, double> func = wrap<bool, int, double, foo>;
    return 0;
}

2voto

max66 Points 4276

Peut-être que tu peux faire wrap en deux étapes : (1) une structure modèle qui reçoit TRet y TArgs... et (2) un modèle statique func() qui reçoivent un Fun<TRet, TsArgs...> paramètre du modèle.

Quelque chose comme suit

template <typename TRet, typename... TsArgs>
struct wrap
 {
   template <Fun<TRet, TsArgs...> F>
   static TRet func (TsArgs ... args)
    { return F(args...); }
 };

que vous pouvez utiliser de cette façon

Fun<bool, int, double> func = wrap<bool, int, double>::func<foo>;

Voici un exemple complet de fonctionnement

#include <iostream>

template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);

template <typename TRet, typename... TsArgs>
struct wrap
 {
   template <Fun<TRet, TsArgs...> F>
   static TRet func (TsArgs ... args)
    { return F(args...); }
 };

bool foo(int x, double y)
 { return x < y; }

int main()
 {
   Fun<bool, int, double> func = wrap<bool, int, double>::func<foo>;

   std::cout << func(1, 2.0) << std::endl;
 }

2voto

max66 Points 4276

Si vous pouvez utiliser C++17, vous pouvez utiliser auto pour le paramètre du modèle.

Cela peut simplifier beaucoup ma réponse précédente.

Ou mieux : simplifier l'utilisation du wrapper.

Si vous définissez un wrapHelper La structure est la suivante

template <typename T, T>
struct wrapHelper;

template <typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
struct wrapHelper<Fun<TRet, TsArgs...>, F>
 {
   static TRet func (TsArgs ... args)
    { return F(args...); }
 };

vous pouvez écrire wrapper en utilisant auto comme suit

template <auto X>
struct wrap : public wrapHelper<decltype(X), X>
 { };

De cette façon, il n'est pas nécessaire d'expliciter le type de retour ( TRet ) et les types d'arguments ( TsArgs... ) : ils sont déduits (dans wrapHelper ) de foo .

Donc, au lieu de

Fun<bool, int, double> func = wrap<bool, int, double>::func<foo>;

vous devez écrire

Fun<bool, int, double> func = wrap<foo>::func;

ou également

auto func = wrap<foo>::func;

Voici un exemple de compilation complète

#include <iostream>
#include <type_traits>

template <typename TRet, typename... TsArgs>
using Fun = TRet (*)(TsArgs...);

bool foo(int x, double y)
 { return x < y; }

template <typename T, T>
struct wrapHelper;

template <typename TRet, typename... TsArgs, Fun<TRet, TsArgs...> F>
struct wrapHelper<Fun<TRet, TsArgs...>, F>
 {
   static TRet func (TsArgs ... args)
    { return F(args...); }
 };

template <auto X>
struct wrap : public wrapHelper<decltype(X), X>
 { };

int main()
 {   
   auto func { wrap<foo>::func };

   static_assert( std::is_same<decltype(func), Fun<bool, int, double>>{} );

   std::cout << func(1, 2.0) << std::endl;
 }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X