0
votes

Passer la fonction en tant qu'argument de modèle à une classe

Je veux passer des fonctions comme arguments de modèle mais je n'arrive pas à les faire fonctionner. J'ai écrit beaucoup de classes de modèles dans le passé, mais en n'utilisant que des types "normaux" comme arguments. J'ai déjà recherché ce problème, mais rien ne semble convenir ici. Je suis donc bloqué.

Voici ce que je veux réaliser: J'ai quelques fonctions de bibliothèque spécifiques de type que je veux encapsuler. Je sais qu'il existe également d'autres façons de le faire (par exemple l'héritage) mais comme je veux aussi en apprendre un peu ici, je veux le faire avec l'approche modèle.

Quoi Je veux réaliser:

template<typename T>
struct SetFunction
{
  inline ret_code operator()(someArgs, T value) const {return E_Fail;}
}

template<typename T>
struct GetFunction
{
  inline ret_code operator()(someArgs, T& value) const {return E_Fail;}
}

//template specialization:
template<>
struct SetFunction<int>
{
  inline ret_code operator()(someArgs, T value) const
  {
    //some other code
    return libraryFunctionWriteInt(someArgs, value);
  }
}

template<>
struct GetFunction<int>
{
  inline ret_code operator()(someArgs, T& value) const
  {
    //some other code
    return libraryFunctionReadInt(someArgs, &value);
  }
}
//do the specialization for all other types as well

template<class T, typename T_get_function = GetFunction<T>(), typename T_set_function = SetFunction<T>()>
MyType
{
public:
  MyType(someArgs)
  {
    if(T_get_function(someArgs, &_value) == E_Fail)
    {
      throw someting;
    }
  }

  bool SetValue(T value)
  {
    _value = value;
    //maybe some other code
    return T_set_function(someArgs, _value) == E_Success;
  }

  bool GetValue(T &value)
  {
    //maybe some other code
    return T_get_function(someArgs, &_value) == E_Success;
  }

private:
  T _value;
}

//and then eventually using it (maybe using some typedefs as well)
MyType<int> myIntObject(someArgs);
...
int writeVal = 10;
myIntObject.SetValue(writeValue);
...
int readVal;
myIntObject.GetValue(&readValue);

Peut-être aussi en utilisant des typedefs:

typedef MyType<int> MyIntType;

Ce que j'ai fait jusqu'ici:

MyType<int> myIntObject(...);
...
int writeVal = 10;
myIntObject.Write(writeVal);
...
int readVal;
myIntObject.Read(&readVal);

Maintenant j'obtiens des erreurs de compilation: liste d'expressions traitée comme une expression composée dans un cast fonctionnel sur ces deux lignes où je appelez la T_set_function / T_get_function . J'ai également essayé de transmettre les fonctions de la bibliothèque directement en tant qu'arguments de modèle et de ne définir aucune fonction par défaut, mais je n'ai pas pu le faire fonctionner de cette façon également.

Presque tous les livres, articles et exemples I lu jusqu'à présent ne traitent que de passer des types "normaux" comme arguments de modèle, mais comme stl utilise également des fonctions de passage, je veux vraiment savoir comment faire cela.


3 commentaires

Je ne peux pas comprendre ce que tu veux vraiment. La SetFunction n'a pas défini de fonction mais elle est utilisée comme foncteur. Donc je n'ai aucune idée de quel est le but?


Ce code horriblement cassé et comme vous le souhaitez, il est possible de le déclarer uniquement en c ++ 20 (après avoir quasiment tout remplacé par une syntaxe appropriée)


Ouais. Je dois admettre que les noms "GetFunction / SetFunction" sont plutôt mal choisis. C'était plutôt comme des getters et des setters de valeur. La lecture / écriture est donc probablement plus appropriée. Le but est d'encapsuler un tas de fonctions de lecture / écriture de bibliothèque comme par ex. write_int32 (int i) / read_int32 (int * i) dans cette classe et mettez des fonctionnalités autour d'elle. Les environs sont toujours les mêmes. Seul l'appel à la bibliothèque est différent. J'ai essayé différentes manières et je me suis retrouvé quelque part, je l'ai dépouillé et posté ici. Quoi qu'il en soit ... résolu et j'ai compris comment cela fonctionne. Alors merci à tous.


3 Réponses :


1
votes

Il y a du code incomplet en ce qui concerne les arguments de l'opérateur, mais la syntaxe

template<class T, T_get_function getter = GetFunction<T>{}, 
              T_set_function setter = SetFunction<T>>{}

est incorrecte. typename T_get_function = suggère un paramètre de type de template, tandis qu'après = vient une expression GetFunction () , pas un déclarateur.

Il devrait be

template<class T, typename T_get_function = GetFunction<T>, 
              typename T_set_function = SetFunction<T>>

Ensuite, il n'est pas clair comment vous vous attendez à ce que T_get_function :: operator () fonctionne sans instance de classe. il doit être statique ou vous devez avoir une instance.

template<class T, typename T_get_function = GetFunction<T>(), 
                  typename T_set_function = SetFunction<T>()>

dans ce cas particulier, typename et class ont la même signification chose et n'est pas nécessaire là-bas. Mais nous ne savons pas quelle T_get_function est là alors? le mettre comme paramètre de classe du modèle et l'assignation de la classe par défaut est une fonctionnalité C ++ 20.

Opérateur et renvoie un pointeur vers une variable, vous ne pouvez pas l'utiliser comme référence (et vous n'avez pas besoin de faire ça). Ce métacode contient plusieurs dizaines de problèmes allant de manquants; à une syntaxe incorrecte et à des mots-clés et déclarations manquants. Si vous vous concentrez sur la norme C ++ antérieure à 2020, vous devriez réécrire cela à partir de zéro, sinon utilisez la réponse de Klaus comme guide.


3 commentaires

Merci, cela a résolu mon problème. Je ne sais pas d'où j'ai "volé" ce truc GetFunction (), mais je suis sûr que je l'ai copié quelque part. Mais maintenant, j'ai l'idée de ce qui n'allait pas et je comprends comment cela fonctionne.L'opérateur & dans la fonction GetFunction est correct car la fonction de bibliothèque que j'appelle attend un pointeur ici (la valeur de retour de la fonction de bibliothèque est le statut et la valeur est renvoyé via ce paramètre (out).


"Norme C ++ antérieure à 2020" ??? Mon code fonctionne avec tous les compilateurs actuels (C ++ 17) Vous devriez donc changer votre réponse en "avant 2017"


@Klaus, oui, parce que vous avez complètement changé d'approche et utilisé auto sans valeur par défaut pour un paramètre de type, auto et les valeurs par défaut avec non-type seraient c ++ 2a (la plupart des compilateurs récents prennent déjà en charge cela)



1
votes

Je ne sais pas si j'attrape votre question, mais d'après le titre que j'ai lu, vous voulez passer une fonction comme paramètre de modèle. C'est assez simple, même si vous le souhaitez avec des paramètres de fonction ou non et avec ou sans valeur de retour.

Exemple:

template < auto func >
struct X
{   
    template < typename ... PARMS >
    static auto call(PARMS&& ... parms)
    {
        return func(parms...);
    }
};  

void func1()           { std::cout << "1" << std::endl; }
void func2(int value ) { std::cout << "2 with " << value << std::endl; }
int  func3()           { std::cout << "With retval" << std::endl; return 987; }

int main()
{   
    X<func1>::call( );
    X<func2>::call( 123 );
    std::cout << "Get retval" << X<func3>::call() << std::endl;
}   


1 commentaires

Cela a l'air vraiment soigné et simple. J'essaierai celui-là plus tard ... merci!



1
votes

GetFunction et SetFunction est un foncteur, vous avez donc besoin d'une instance de celui-ci pour appeler son opérateur d'appel .

p> Pourriez-vous remplacer ces parties

  bool SetValue(T value)
  {
    _value = value;
    //maybe some other code
    return T_set_function{ /*Functor constructed*/ }(someArgs, _value) == E_Success;
  }

  bool GetValue(T &value)
  {
    //maybe some other code
    return T_get_function{ /*Functor constructed*/ }(someArgs, &_value) == E_Success;
  }

  if(T_get_function{ /*Functor constructed*/ }(someArgs, &_value) == E_Fail)
  {
    throw someting;
  }

comme @ Swift-FridayPie l'a dit, vous devez également réorganiser la partie des paramètres du modèle.


1 commentaires

Merci! J'ai juste essayé la solution de @ Swift-Friday-Pie et cela a fonctionné. Cela est parfaitement logique. Sujet démystifié. ;-)