8
votes

Comment puis-je simplifier cette "variable comme paramètre de modèle" en C ++?

Comment puis-je simplifier ce code?

mfer::i_value* make_empty_value(mfer::tag tag_)
{
    return memory_manager::instance().add(new mfer::t_value<tag_>());
}
  • mff-mfre :: étiquette est énumération, définie comme Enum tag {}; code> dans l'espace de noms de noms. p> li>

  • mffre :: i_value est une classe abstraite. P>

    template <mfer::tag tag_type>
    class t_value : public i_value {};
    
  • MFF MFER :: T_Value est une classe modélisée comme, p>

    class i_value {};
    


6 commentaires

S'il vous plaît ne postez pas votre code comme une image. Postez-le comme le texte dans la réponse.


Vous pouvez modifier ces si s sur commutateur / case si mfre :: tag :: mwf _ * sont des constantes. Cela peut améliorer la lisibilité.


Pouvez-vous partager la définition de la classe t_value ? Au moins les parties pertinentes où tag_type influence la définition de cette classe. C'est tout à fait possible, basé sur ce que vous faites, que t_value ne doit pas être une classe de modèle du tout. Tag_Type pourrait être transmis dans le constructeur.


@Forcebru merci pour votre conseil. Et plus, existe-t-il une solution essentielle pour ce code? Je pense que la conversion de commutation aidera mais elle ne pouvait pas résoudre la complexité essentielle de ce code.


@selbie C'est ma faute mais le partage de codes sera difficile, car ce sera long. Mais il est clair, la classe t_value est fortement liée au tag_type.


Je voudrais utiliser un commutateur


5 Réponses :


0
votes

Pas directement à l'aide de votre exemple, mais vous pouvez faire quelque chose sur les lignes ci-dessous, c'est convertir Enum en un type.

enum Type {
  Type_A,
  Type_B,
};

template <Type T>
struct Enum2Type {
  constexpr static const Type type = T;
};

template <typename T>
mfer::i_value* make_empty_value(T tag_type)
{
    return memory_manager::instance().add(new mfer::t_value<tag_type.type>());
}

auto val = make_empty_value(Enum2Type<Type_A>());
auto val2 = make_empty_value(Enum2Type<Type_B>());


4 commentaires

Mais si j'utilise ce code, je ne peux pas passer de la variable à travers cette fonction, n'est-ce pas?


Si vous voulez dire faire l'argument de make_empty_value variable, alors non, vous ne pouvez pas. Un modèle nécessite une certaine valeur qu'il peut voir une heure de compilation. À un moment donné, vous devrez utiliser un cas de commutation si son paramètre d'exécution.


Je vois. ; (Je m'attendais à ce que la situation puisse mettre en œuvre de cette façon sera plus habituelle, alors je croyais qu'il y ait un modèle pour ces codes.


Une autre façon serait d'utiliser Dispatching dans le constructeur de MFF :: t_value . Dans ce cas, vous n'avez pas besoin d'écrire le boîtier de commutation dans make_empty_value , mais il devra ensuite créer un constructeur pour chaque valeur d'énorme. Donc, vous voyez, à un moment donné, vous devrez développer toutes vos options si vous utilisez le paramètre d'exécution :)



1
votes

Vous pouvez mapper les balises sur une méthode d'usine;

mfer::i_value* make_empty_value(mfer::tag tag_)
{
    static TagMap factory = create_tag_map();

    auto it = factory.find( tag_ );      
    if( it != factory.end() )
    {
        return  memory_manager::instance().add( it->second() );
    }

    return nullptr;
}


1 commentaires

Mais s'il n'en utilise qu'une seule fois, il écrit même plus code pour créer le modèle d'usine pour une utilisation unique.



1
votes

Vous pouvez créer une fonction de modèle récursif si la valeur énumérée suit un motif connu (par défaut la valeur énumérée suivante est égale à énumérer +1): xxx

si vous ne connaissez pas la constitutive Règle de votre énumérer, vous ne pouvez pas faire cela (la loi constitutive générale est comme dans cet exemple, x [i + 1] = x [i] +1, ou x [i + 1] = x [i] << 1 ( changement de gauche).) Sinon, leur n'est pas un moyen de itérer sur des éléments d'une énumération.

Remarque: la fonction Compute sera certainement inlinée, mais sans doute que vous puissiez utiliser Attribut spécifique du compilateur sous forme __ forcerinline avec msvc ou __ attribut __ ((__ toujours_inline __)) avec gcc ou clang.


0 commentaires

0
votes

La seule portée de la simplification que je vois consiste à éliminer le code de la chaudière en remplaçant par une macro fixe. Cela apaisera le spectateur.

au lieu de tant de si-else si code>, faites-le un commutateur / case code> comme ci-dessous: p>

#define CASE(TAG) \
  case TAG: return memory_manager::instance().add(new mfer::t_value<TAG>())

mfer::i_value* make_empty_value(const mfer::tag tag_)
{
  switch(tag_) {
  {
  CASE(mfer::tag::mwf_ble);
  CASE(mfer::tag::mwf_chn);
  CASE(mfer::tag::mwf_blk);
  //...
  default: break;
  }
  return nullptr;
}

#undef CASE


0 commentaires

2
votes

Avec un peu de modèle, nous pouvons obtenir la fonction d'usine jusqu'à: XXX PRE>

Code complet ci-dessous. P>

La carte génératrice i_value est construite au moment de la compilation, permettant une recherche de temps constante. p>

contraintes: p>

  • Les valeurs de l'énum doivent être consécutives, mais elles n'ont pas besoin de commencer à zéro. p> li>

  • Cette démo nécessite C ++ 14. Il peut être facilement adapté pour travailler avec C ++ 11. Pour C ++ 03, nous voudrions tendre la main pour booster mpl ou boost_pp. P> li> ul>

    Exemple de fonctionnement complet: p>

    I have tag 0
    I have tag 1
    tag 1 destroyed
    tag 0 destroyed
    


2 commentaires

Puis-je vous demander pourquoi vous avez enveloppé Void () aux fonctions de T_Value? Ça fait mieux?


Croyez-le ou non, l'emballage des opérations OSTREAM en annulation empêche le Xcode de mal former le code. Il s'agit également d'une manière portable d'indiquer que vous ignorez délibérément la valeur de retour.