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;} }
3 Réponses :
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
isTwo
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;} }
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 .)
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é.
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; }
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
etisTwo
pourraient être implémentés en termes destd :: is_same
, si vous souhaitez les simplifier. ... Ce qui signifie qu'ils peuvent également être simplement remplacés paris_same
. Ils pourraient également être combinés en tant que modèle de variable, qui pourrait être élargi si nécessaire.