5
votes

Autoriser le paramètre de modèle à n'être que certains types et décider de l'action en fonction de celui-ci

Disons que j'ai deux classes MyClass_one , MyClass_two

Et j'ai une fonction qui les accepte uniquement comme premier paramètre

template<typename T> isOne{ static const bool value = false}
template<> isOne<MyClass_one>{ static const bool value = true}

template<typename T> isTwo{ static const bool value = false}
template<> isTwo<MyClass_two>{ static const bool value = true}

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
  if( isOne<T>::value ) { cout << "im one" << endl;}
  else if ( isTwo<T>::value){ cout <<"im two" << endl;}
}


4 commentaires

Spécialisation des modèles?


Voulez-vous élaborer? Je suis assez novice dans les modèles


Vous pouvez spécialiser le modèle pour chacun des types d’arguments de modèle qui vous intéressent.


isOne et isTwo pourraient être implémentés en termes de std :: is_same , si vous souhaitez les simplifier. ... Ce qui signifie qu'ils peuvent également être simplement remplacés par is_same . Ils pourraient également être combinés en tant que modèle de variable, qui pourrait être élargi si nécessaire.


3 Réponses :


5
votes

Si vous pouvez utiliser C ++ 17, vous pouvez utiliser if constexpr :

#include <iostream> 
#include <type_traits>
#include <vector> 

class MyClassOne {}; 
class MyClassTwo {}; 

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
  if constexpr ( std::is_same_v<T, MyClassOne> ) 
    std::cout << "im one" << std::endl;
  else if constexpr ( std::is_same_v<T, MyClassTwo> )
    std::cout <<"im two" << std::endl;
  else
    static_assert(false, "Only MyClassOne and MyClassTwo are permitted first arguments.");
}
int                                                                                                                                         
main(int argc, char **argv) { 

    MyClassOne one; 
    MyClassTwo two; 

    doSomething(one, 1.5, two); 
    doSomething(two, 'c', one);

    std::vector<MyClassOne> onesVector;
    doSomething(onesVector, 1.0); 

}  

Bien sûr, isOne :: value et isTwo :: value doivent être des variables static constexpr .

Si vous voulez vérifier les types du premier argument de fonction, la même approche est valable, seulement il n'y a pas besoin de quelque chose comme isOne et isTwo , vous pouvez utiliser std :: is_same_v pour voir si le premier argument est MyClassOne ou MyClassTwo :

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two){
  if constexpr ( isOne<T>::value ) { cout << "im one" << endl;}
  else if constexpr ( isTwo<T>::value){ cout <<"im two" << endl;}
}


2 commentaires

Cependant, cela compilerait même si je passais par exemple le vecteur comme premier paramètre, mon point est qu'il ne devrait même pas compiler, je modifierai la question pour que ce ne soit pas déroutant


Vous pouvez résoudre ce problème en ajoutant un static_assert au code de tmaric , @Darlyn. (Notez que static_assert n'a pas besoin de vérifier à la fois MyClassOne et MyClassTwo , il doit seulement vérifier l'un des types qui ' d ont été interceptés par l'une des branches précédentes, pour garantir que le résultat est toujours false sans le coder explicitement en dur comme false . Vérification soit individuellement, soit les deux, aura le même résultat .)



2
votes

Je vous suggère de diviser votre fonction en deux parties. Conservez la partie itérative doSomething et séparez ce que vous voulez réellement faire.

template<typename T> void theThing(T one);

template<>
void theThing<MyClass_one>(MyClass_one one) {
    cout << "im one" << endl;
}

template<>
void theThing<MyClass_two>(MyClass_two one) {
    cout << "im two" << endl;
}

template<typename T, typename ... Ts>
void doSomething(T one, Ts...two) {
    theThing(one);
}

De cette façon, vous pouvez avoir des choses spécialisées pour chaque classe que vous souhaitez utiliser. Bonus, il ne se compilera pas pour les types pour lesquels theThing n'est pas spécialisé.


0 commentaires

3
votes

sans surcharge

mais la surcharge ici simplifie le code:

template<typename ... Ts>
void doSomething(MyClass_one, Ts...two){
    cout << "im one" << endl;
}

template<typename ... Ts>
void doSomething(MyClass_two, Ts...two){
    cout <<"im two" << endl;
}

0 commentaires