Forum Programmation.c++ Petite question de c++ pour égayer votre vendredi

Posté par  . Licence CC By‑SA.
Étiquettes :
2
28
mai
2021

Bonjour,
je suis en train de coder une toute petite librairie et je bute sur un petit problème.
voici le code actuel (simplifié):

template <typename A, typename B>
class Function {
public:
    Function() {
        register_inputs();
    }

    Input<A> in0;
    Input<B> in1;
    void register_inputs() {
        inputs.insert(&in0);
        inputs.insert(&in1);
    }

private:
    std::unordered_set<InputBase*> inputs;
}

Ca marche comme ça, mais j'aimerais pouvoir faire ceci, avec une macro (ou autre) :

CREATE_INPUT(A, in0);
CREATE_INPUT(B, in1);

qui me générerait cette partie automatiquement :

    Input<A> in0;
    Input<B> in1;
    void register_inputs() {
        inputs.insert(&in0);
        inputs.insert(&in1);
    }

Histoire de ne pas oublier de mettre les "inputs" dans le conteneur. Et puis c'est plus joli.

Je cherche un peu à me couper les cheveux en 4, mais c'est aussi un exercice pour apprendre de nouvelles choses en C++. J'ai d'ailleurs découvert les X_Macro qui pourraient peut-être résoudre mon problème mais je suis un peu bloqué.

j'ai aussi découvert m4 qui pourrait résoudre mon problème en l'utilisant comme pré-préprocesseur (lol), mais j'aimerais savoir si c'est possible de le faire uniquement en c++.

Merci, bon dredi

  • # # define

    Posté par  (site web personnel) . Évalué à -1.

    on doit pouvoir faire ça avec un #define, qui va être expansé par le precompilateur.

  • # Autre approche

    Posté par  (site web personnel) . Évalué à 4.

    Probablement le mieux est d'éviter tant que possible d'utiliser des pré-processeurs ou des générateurs de code. Ce n'est pas qu'ils soient maléfiques ou quoique ce soit, mais ils ajoutent une couche de complexité et ne sont pas forcément bien intégrés aux IDEs et autres outils (et puis le préprocesseur du C est en réalité maléfique)

    Sans connaître a priori ta bibliothèque on ne peut que donner que des conseils très généraux mais il me semble que tu as plutôt intérêt à revoir ta modélisation: il me semble que ta présentation actuelle va certainement marcher mais met en avant des traits qui sont purement liés à l'implémentation que tu as choisie et pas du tout au problème que tu veux résoudre. Mettre en avant les traits intrinsèques au problème et cacher au maximum les détails d'implémentation est ce qui fait la force et la grande difficulté de la programmation par objets.

    Pour te familiariser avec cette perspective tu peux lire à propos du domain model – désolé pour l'inglishe – p.ex. en commeçant ici https://www.martinfowler.com/bliki/AnemicDomainModel.html

    Dans ton cas possibilité serait d'unifier les types A et B dans une classe générale – qui contiendrait A et B comme sous-types. De toutes façons to programme qu'un Input et Input sont susceptibles d'être insérés quelque part.

  • # c'est un tuple que tu veux non?

    Posté par  . Évalué à 5. Dernière modification le 31 mai 2021 à 11:08.

    par contre, y'a pas vraiment d'initialisation du tuple; va falloir que les constructeurs par défaut fassent leur taff :)

    #include <iostream>
    #include <tuple>
    #include <unordered_set>
    
    struct bark {
        virtual void ouaf() = 0;
    };
    
    struct Plop : public bark {
        Plop() { std::cout << "Plop" << std::endl; }    
        void ouaf(){ std::cout << " ouaf plop" << std::endl; }
    };
    
    struct Plip : public bark {
        Plip() { std::cout << "Plip" << std::endl; }    
        void ouaf(){ std::cout << " ouaf plip" << std::endl; }
    
    };
    
    template<typename...Inputs>
    class Function {
    
       std::tuple<Inputs...> in;
    
    
       void register_inputs() {
            std::apply([&](auto&&... args) {((inputs.insert(&args)), ...);}, in);
        }
    
    
       std::unordered_set<bark*> inputs;
    
    public:   
    Function() { register_inputs() ;}
          void carp() {
           for(auto& chien : inputs) {
               chien->ouaf();
           }
       }
    
    };
    
    int main()
    {
        Function<Plop,Plip,Plip, Plop> inputs;
    
        inputs.carp();
    }

    mais tu peux très bien filer le tuple au constructeur, et le l'affecter au membre in; puis faire l'enregistrement; note bien, à partir du moment où l'on stock le tout dans un tuple, l'usage du set peut potentiellement être superflu; ça dépends des traitement derrière; l'avantage du set c'est que partout on aura un set de machin alors que pour les tuples ce sera autant de types différents.

    lorsque je code j'essaye au maximum d'éviter de devoir ajouter des morceau à 4/5 endroits dès que je veux ajouter un truc.

    Il ne faut pas décorner les boeufs avant d'avoir semé le vent

    • [^] # Re: c'est un tuple que tu veux non?

      Posté par  . Évalué à 4.

      a noter que tu devrait pouvoir faire avec le contructeur qui prends le tuple pour l'initialisation un
      (donc

      explicit Function(std::tuple<Inputs...> &&entrer){ 
            in=entrer; 
            register_inputs();
          }
      
      
      [...]
      
          auto maka=Function(std::tuple(Plip(),Plip()));
          maka.carp();

      j'imagine qu'il doit y'avoir moyen de se passer des std::tuples dans les constructeurs

        Function(Inputs... entrer){ 
            in=std::tuple(entrer...); 
            register_inputs();
          }
      
      [...]
      
      auto bonk=Function(Plop(),Plop());
          bonk.carp();

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: c'est un tuple que tu veux non?

        Posté par  . Évalué à 1.

        Merci, oui c'est ça qu'il me fallait !!!
        Je ne connaissais pas les tuples.
        Il va falloir que je résiste à la tentation de coder ça cet après-midi…

        • [^] # Re: c'est un tuple que tu veux non?

          Posté par  . Évalué à 4.

          en terme technique c'est tuple et fold expression

          (le std::apply avec les … )

          c'est du c++17

          sinon faut générer un index, et y aller à coup de get<> et template de n-1 à 0 (attention à l'ordre de l'appel récursif pour pas inverser l'ordre si c'est important, même si là c'est un set, dans d'autre cas ça pourrait avoir son importance)

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.