web-dev-qa-db-fra.com

comment faire un type de type if else selon le modèle c ++?

// template specialization
#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
  public:
    mycontainer (T arg) {element=arg;}
    T increase () {

    //if(T.type==int)//how to do this or something similar?
    //do this if an int
    return ++element;

    //if(T.type==char)
     //if ((element>='a')&&(element<='z'))
      //element+='A'-'a';
      //return element;

    }
};

Je sais comment écrire une spécialisation de modèle et effectuer une définition de classe entière distincte uniquement pour le type char.

Mais si je voulais tout gérer en un seul bloc de code?

Comment puis-je vérifier si T est un int ou un char?

28
user494461

Vous pouvez utiliser typeid:

if (typeid(T) == typeid(int))

Ou vous pouvez utiliser le trait de type std::is_same:

if (std::is_same<T, int>::value)
26
Joseph Mansfield

Ce que vous voulez est probablement quelque chose comme un si vous voulez le compiler . Malheureusement, C++ 11 n’a pas de support natif pour une telle construction de langage.

Cependant, si vous voulez juste vérifier si deux types sont identiques, le trait de type std::is_same<> devrait vous aider:

#include <type_traits> // <== INCLUDE THIS STANDARD HEADER

// class template:
template <class T>
class mycontainer 
{
    T element;
public:
    mycontainer (T arg) {element=arg;}
    T increase () 
    {
        if (std::is_same<T, int>::value)   // <== THIS IS HOW YOU WOULD USE IT
            return ++element;

        if (std::is_same<T, char>::value)  // <== THIS IS HOW YOU WOULD USE IT
        {
            if ((element>='a') && (element<='z'))
                element+='A'-'a';
        }

        return element;
    }
};

Cependant, gardez à l'esprit que la condition est évaluée au moment de l'exécution, même si la valeur de is_same<T, int>::value est connue au moment de la compilation. Cela signifie que les deux la true et la branche false de l'instruction ifdoit être compilée!

Par exemple, ce qui suit ne serait pas légal:

if (std::is_same<T, int>::value)
{
    cout << element;
}
else if (std::is_same<T, my_class>::value)
{
    element->print();  // Would not compile when T is int!
}

De plus, comme le précise Xeo correctement indiqué dans les commentaires, le compilateur émettra probablement des avertissements, car votre condition sera toujours évaluée à true ou à false, de sorte qu'une des deux branches contiendra du code inaccessible.

13
Andy Prowl

Que diriez-vous d'une simple surcharge?

// in the private section
static int& do_increase(int& i){ return ++i; }
static char& do_increase(char& c){
  if(c >= 'a' && c <= 'z')
    c += 'A' - 'a';
  return c;
}
template<class U>
static U& do_increase(U& arg){
  // some default implementation?
  return arg;
}

(Notez que la norme ne garantit pas l'ordre alphabétique des valeurs numériques de char.)

Ensuite, appelez simplement cela dans increase comme return do_increase(element);.

7
Xeo

Vous pouvez utiliser une spécialisation de modèle explicite

#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
  public:
    mycontainer (T arg) {element=arg;}
    T increase();
};


template<>
int mycontainer<int>::increase(){
    return ++element;
}

template<>
char mycontainer<char>::increase(){
    if ((element>='a')&&(element<='z'))
       element+='A'-'a';
    return element;
}

int main(){
        mycontainer<int> A(10);
        mycontainer<char> B('x');

        cout << A.increase() <<endl;
        cout << B.increase() <<endl;
        return 0;
}
7
xvan

La solution habituelle consiste ici à transmettre à une fonction surchargée .__ avec un argument supplémentaire. Quelque chose comme:

template <typename T>
class MyContainer
{
    T increase( int const* ) { /* special treatment for int */ }
    T increase( ... )        { /* default treatment         */ }
public:
    T increase()
    {
        return increase( (T const*)0 );
    }
};

Avec un peu d'imagination, vous pouvez faire toutes sortes de distinctions Si vous créez les fonctions cible avec les modèles supplémentaires Arguments, vous pouvez même tirer parti de SFINAE: design L'argument factice pour que la substitution du type de modèle échoue et que la fonction . Et Étant donné que toutes les fonctions sont en ligne, il est probable qu’il n’y aura pas de surcoût supplémentaire, à condition d’optimiser.

3
James Kanze

Ceci va dans le sens de la réponse d’Andy Prowls mais est tout fait lors de la compilation en utilisant une classe d’aides minimale avec spécialisation.

Dans ce cas, vous avez un assistant qui effectue la spécialisation, mais vous pouvez également demander à la classe d'assistance de prendre un booléen, puis d'utiliser quelque chose comme std::is_same<T, int>::value pour transmettre cette valeur en tant que paramètre de modèle.

template <typename T>
struct myContainerHelper;
{
    // General Case
    static inline T increase(T element)
    {
        return ++element;
    }
};

template <>
struct myContainerHelper<char>
{
    // Specific case
    static inline char increase(char element)
    {
        if ((element>='a')&&(element<='z')) element+='A'-'a';
        return element;
    }
};

template <class T>
class mycontainer 
{
    T element;
public:
    mycontainer (T arg) {element=arg;}
    T increase () 
    {
        return myContainerHelper<T>::increase(element);
    }
};

Cela vous permet de spécialiser uniquement la fonction unique à la place de la classe entière. J'utilise une classe de modèles avec la statique car je suis habitué aux limitations VS2012 avec la spécialisation partielle pour les modèles de fonctions.

0
NtscCobalt