2010-10-12 55 views
4

Mon professeur m'a confié cette tâche.Erreur logique dans le modèle de fonction

Mettre en oeuvre une fonction générique appelée Max, qui prend 3 arguments de type générique et un rendement maximal de ces 3. Mettre en œuvre une fonction spécialisée pour char * types.

Voici mon code:

#include <iostream> 
#include <string> 

using namespace std; 

template<typename T> 
T Max(T first,T second,T third) 
{ 
    if(first > second) 
    { 
     if(first > third) 
     { 
      return first; 
     } 
     else 
     { 
      return third; 
     } 
    } 
    else if(second > third) 
    { 
     return second; 
    } 
    else 
    { 
     return third; 
    } 
} 


template<> 
char* Max(char* first,char* second,char* third) 
{ 
    if(strcmp(first, second) > 0) 
    { 
     if(strcmp(first, third) > 0) 
     { 
      return first; 
     } 
     else 
     { 
      return third; 
     } 
    } 
    else if(strcmp(second, third) > 0) 
    { 
     return second; 
    } 
    else 
    { 
     return third; 
    } 
} 

int main(void) 
{ 
    cout << "Greatest in 10, 20, 30 is " << Max(10, 20, 30) << endl; 

    char a = 'A'; 
    char b = 'B'; 
    char c = 'C'; 
    char Cptr = *Max(&a, &b, &c); 
    cout << "Greatest in A, B ,C is " << Cptr << endl; 

    string d = "A"; 
    string e = "B"; 
    string f = "C"; 
    string result = *Max(&d, &e, &f); 

    cout << "Greatest in A, B, C is " << result << endl; 
} 

Sortie:

plus grand en 10, 20, 30 est 30
plus grand en A, B, C est C
Le meilleur en A, B, C est A

Problème:

Si je passe en fonction des types de données ombles Max A, B, C, elle retourne C, mais si je passe chaîne A datatypes, B, C retourne A.

Pourquoi Est-ce que ça retourne A ici?

Répondre

4

Il y a deux problèmes ici. Les deux autres réponses ont déjà décrit le problème avec votre troisième appel.

Mais votre deuxième appel est également erroné:

char a = 'A'; 
char b = 'B'; 
char c = 'C'; 
char Cptr = *Max(&a, &b, &c); 

Cela devrait produire un comportement non défini depuis strcmp requiert des chaînes terminées zéro, mais ce n'est pas ce que vous nourrissez dans la fonction. Plutôt, vous passez des pointeurs aux valeurs individuelles char et strcmp a le droit de s'étouffer à ce sujet. Fondamentalement, tout peut arriver et que votre code fonctionne est un pur hasard.

La bonne façon d'appeler cette surcharge serait juste pour passer char s, ou pour passer des chaînes de style C:

char C = Max(a, b, c); 

// or: 
char as[] = "a"; 
char bs[] = "b"; 
char cd[] = "c"; 
char* result = Max(as, bs, cd); 

Sinon, vous pouvez passer directement les chaînes littérales.

Enfin, une note sur le style. Vous char* la spécialisation peut être considérablement réduite si vous « tricher » un peu en convertissant les chaînes char* entrants bon std::string s et réutiliser la version générique de Max:

template<> 
char* Max(char* first,char* second,char* third) 
{ 
    return Max(string(first), string(second), string(third)); 
} 

(D'accord, cela est probablement moins efficace mais dans la plupart des cas, cela peut être ignoré en toute sécurité.)

Encore une remarque: l'affectation vous a explicitement demandé de spécialiser le modèle de fonction pour char* afin que votre réponse soit correcte. Cependant, une alternative serait surcharger la fonction au lieu de la spécialiser. Pour les modèles de fonction (par opposition aux modèles de classe), c'est la façon habituelle lorsque vous ne souhaitez pas plus d'arguments de modèle:

char* Max(char* first,char* second,char* third) 
{ 
    return Max(string(first), string(second), string(third)); 
} 

Notez que la seule différence est le manque template <> en face de l'en-tête de la fonction.

2
string result = *Max(&d, &e, &f); 

Cette ligne est votre problème. Vous passez le pointeur sur la chaîne afin qu'il renvoie en fait l'adresse du pointeur la plus haute. Gardez à l'esprit que la pile se développe vers le bas de sorte que le début de la pile a l'adresse la plus élevée. Chaque allocation de pile suivante (c'est-à-dire une déclaration de variable dans ce cas) lancera une adresse de pile progressivement plus basse et, par conséquent, "A" apparaîtra comme la plus grande valeur.

Si vous écrivez ceci:

string result = Max(d, e, f); 

Vous obtiendrez la réponse que vous attendez.

2

Dans le premier cas, il utilise la spécialisation de template, dans le second cas, le template générique.

Mais votre problème est la façon dont vous appelez Max dans le second cas:

string d = "A"; 
string e = "B"; 
string f = "C"; 
// you're comparing the string addresses here, not their content 
string result = *Max(&d, &e, &f); 

devrait être:

string d = "A"; 
string e = "B"; 
string f = "C"; 
string result = Max(d, e, f); 

Aussi, je suggère d'utiliser const pointeurs dans la spécialisation char* parce qu'il se tient, vous ne pouvez pas passer autre chose que des pointeurs non-const, ce qui n'est pas exactement le cas courant.

+0

merci pour votre aide. – Searock

1

au lieu de

string result = *Max(*&d, &e, &f)

vous avez besoin

string result = Max(d.c_str(), e.c_str(), f.c_str()) 

Notez que cela fonctionnera si votre fonction prend const char* et non char*. Si vous insistez sur l'utilisation de char *, ce qui est faux, alors vous devrez jeter constness loin

string result = Max(const_cast<char*>(d.c_str()), 

const_cast<char*>(e.c_str()), const_cast<char*>(f.c_str())); 

mais puisque vous utilisez string s, notez que vous pouvez les comparer simplement avec == <> etc.

+0

Que fait 'c_str()'? – Searock

+0

Cela ne fonctionnerait pas: la spécialisation du template prend uniquement 'char *' et non 'const char *'. De plus, cela provoquerait des conversions inutiles à C-String. – ereOn

+0

c_str convertit de chaîne en const char * –