2010-09-03 5 views
0

L'une des méthodes membres de ma classe prend comme argument le type d'énumération: elle produit différents effets secondaires pour différentes énumérations. Je me demandais s'il est possible d'utiliser le modèle comme une table de consultation, deux solutions possibles sont venus à l'esprit, mais aucun d'entre eux ne semble fonctionner:Instancier un modèle avec un type modifié de manière variable

//// 1 //// 

class A { 

    public: 

    enum AEnum : uint8_t { first, second, ... }; 

    private: 

    template<AEnum N, typename T> 
    struct impl { 
     static void do_sth(T t) { ... }; 
    }; 

    template<typename T> 
    struct impl<first, T> { 
     static void do_sth(T t) { ... }; 
    }; 

    public: 


    template<typename T> 
    void do_sth(AEnum e, T t) { 
     impl<e, T>::do_sth(t); 
    } 

} 

//// 2 //// 

class A { 

    public: 

    enum AEnum : uint8_t { first, second, ... }; 

    private: 

    template<typename T_enum, typename T> 
    struct impl { 
     static void do_sth(T t) { ... }; 
    }; 

    template<typename T> 
    struct impl<uint8_t[2], T> { // A::first 
     static void do_sth(T t) { ... }; 
    }; 

    public: 


    template<typename T> 
    void do_sth(AEnum e, T t) { 
     impl<uint8_t[static_cast<uint8_t>(e) + 1u], T>::do_sth(t); 
    } 

} 

Est-il très mauvaise idée de le coder de cette façon?

@Oli Charlesworth

Quel est le problème avec une instruction switch?

Les types pris en charge du second argument de do_sth (T) varient avec la valeur de e, par ex. A :: soutient le premier Intégrales, et A :: seconde conteneurs STL, .: par exemple

template<typename T> 
    void do_sth(AEnum e, T t) { 
     switch(e) { 
      case first: 
       std::cout << &t << std::endl; 
       break; 
      case second: 
       std::cout << t.data() << std::endl; 
       break; 
      default: 
       break; 
    } 

A a; 
a.do_sth(A::first, 0); 
+0

Et ainsi, que devrait-il se passer si e est la deuxième à l'exécution et t est un int? Il semble que toute sélection puisse avoir lieu au moment de la compilation, auquel cas on ne sait pas du tout à quoi l'énumération est nécessaire. – UncleBens

+0

Il n'est pas possible que t soit de type int au moment de l'exécution car il ne sera même pas compilé. J'ai trouvé en rapport à propos de sfinae, pense que ça devrait faire l'affaire. – erjot

Répondre

2

Vous devez faire le AEnum arg un argument de modèle pour do_sth:


template<AEnum e, typename T> 
    void do_sth(T t) { ... } 

... et l'appeler comme a.do_sth<A::first>(0).

Sinon, vous pouvez écrire des fonctions séparées (do_sth_integral, do_sth_container, ...), ou, s'il n'y a qu'un seul cours d'action correcte pour un T, en déduire la valeur enum « correcte » pour un particulier en utilisant T donné metaprogramming/trucs surchargés.

Par exemple, voici un moyen d'écrire deux fonctions qui, par ex. détecter les types numériques et les types de conteneurs: si vous avez passé un T qui a un typedef iterator et une spécialisation de numeric_limits, ou n'a ni


//The extra dummy argument is invalid for types without a nested 
//"iterator" typedef 
template<typename T> 
void do_sth(T t, typename T::iterator * = 0) 
{ 
    //container type code 
} 

//The dummy arg is invalid for types without a 
//std::numeric_limits specialization 
template<typename T> 
void do_sth(T t, 
typename boost::enable_if_c<std::numeric_limits<T>::is_specialized>::type * = 0) 
{ 
    //numeric type code 
} 

Bien sûr, cela échouerait.

S'il n'y a qu'une seule action sensible pour un T particulier, et qu'il est difficile de deviner quelle surcharge utiliser pour un T inconnu, vous pouvez utiliser une classe de traits que les utilisateurs doivent se spécialiser explicitement, ou simplement exiger que les utilisateurs spécialisent une classe "impl" ou dispatching.

Vous ne pouvez pas écrire une fonction qui fait quelque chose comme 3.data(), même si ce chemin de code n'est jamais appelé lorsque le programme s'exécute. Le compilateur ne sait pas qu'il ne sera jamais appelé, et dans tous les cas, il viole le système de type de la langue d'une manière qui est nécessaire pour provoquer une erreur diagnostiquée.

1

Oui, ce que vous avez ne fait pas avons écrit aucun sens. Les instanciations de modèles sont résolues au moment du compilateur, alors que la valeur de e n'est évidemment connue qu'au moment de l'exécution.

Qu'est-ce qui ne va pas avec une instruction switch?

Questions connexes