2
votes

Quand est-ce que j'obtiens l'erreur "définition surchargée nécessaire"?

Prenons cet exemple simple:

#include <iostream>

using namespace std;

void Display(char a, char b, char c)
{
   cout << a << " " << b << " " << c << endl;
}

int main()
{
   Display(2, 3, 4); // Why no syntax error?
   Display(2.0, 3.0, 4.0); // Also no error? O.o
   Display('a', 'b', 'c');
 
   system("pause");
   return 0;
}

Je m'attendais à des erreurs sur les deux premiers appels Display (), qui diraient:

Aucune définition pour Display () qui prend (int, int, int) trouvée.

Aucune définition pour Display () qui prend (double, double, double) trouvée.

Où alors je devrais surcharger Display () et ajouter ceux qui acceptent les paramètres appropriés.

Dans quels cas est-ce que j'obtiens réellement l'erreur de syntaxe? Et pourquoi je n'ai pas eu l'erreur dans ce cas?


10 commentaires

La conversion d'un int en un char fait partie des conversions standard. Plus d'informations sur en.cppreference.com/w/cpp/language/implicit_conversion .


@ πάνταῥεῖ L'OP dit qu'ils s'attendent à obtenir une erreur, non pas qu'ils l'ont fait.


@ πάνταῥεῖ Ha? Il n'y a PAS d'erreur, c'est pourquoi je demande ici ...


@Nathan OMG, je viens de m'en rendre compte. Stupide que je suis :-(


Cela devrait donner des avertissements de troncature mais pas des erreurs. Si vous voulez forcer une erreur, vous devriez regarder explicite .


@SandraK Au moins, le titre de votre question semble m'avoir induit en erreur.


@Tzalumen Pourquoi? Qu'est-ce qui est tronqué?


@Tzalumen Je ne vois pas la troncature. Et où mettriez-vous explicite ? Je ne l'ai jamais vu utilisé que sur les constructeurs et les opérateurs de conversion.


@ FrançoisAndrieux Cela ... pourrait en fait être C ++ 20 qui l'a. décevant.


@ FrançoisAndrieux Je pense que je me trompe en supposant qu'ils ont rendu le spécificateur disponible pour toutes les fonctions. Peut-être qu'ils le feront dans la prochaine révision: /


3 Réponses :


0
votes

Parce que les valeurs sont implicitement converties. Ceci est également appelé conversion de type automatique. Les caractères sont de type entier, donc ils sont threadés comme n'importe quel autre int - attribuer un double ou un float à un int tronquera la valeur.

C'est assez courant, pratiquement tous les langages de programmation auxquels je pense le font.


1 commentaires

@SandraK "Mais dans quels cas j'obtiens réellement l'erreur?" Dans les cas où vous n'avez pas de conversions implicites. Essayez par exemple avec deux types d'énumérations différents, ou un type complexe comme std :: string .



4
votes

Un int peut être converti en char grâce à Conversions standard / Convesions intégrales .

Une prvalue d'un type entier peut être convertie en une prvalue d'un autre type entier. Une prvalue d'un type d'énumération non scopé peut être convertie en une prvalue d'un type entier.

La définition du type entier peut être vue à Concepts de base / Types fondamentaux .

Types bool , char , char16_t , char32_t , wchar_t et les types entiers signés et non signés sont collectivement appelés types intégraux . Un synonyme de type intégral est type entier .


Un double peut également être conerté à un char grâce à Conversions standard / Conversions à intégrale flottante .

Une prvalue d'un type à virgule flottante peut être convertie en une prvalue d'un type entier. La conversion tronque; autrement dit, la partie fractionnaire est supprimée.


0 commentaires

4
votes

C'est ainsi que fonctionne le C ++. Le compilateur essaiera de convertir implicitement le type que vous lui donnez au type dont il a besoin, même s'il s'agit d'une conversion restrictive (une exception a été faite si vous effectuez l'initialisation d'accolades. Là, vous obtenez une erreur). Dans ce cas, il convertira le int que vous lui donnez en un char avec la même valeur et continue.

Étant donné que toutes les valeurs que vous avez fournies sont des constantes de temps de compilation comprises entre [0, 127], cela ne peut jamais échouer et vous ne recevrez même pas d'avertissement indiquant que vous pourriez déborder.

Si vous aviez utilisé quelque chose comme

template<typename T, typename U, typename V>
void Display(T, U, V) = delete;

Vous obtiendrez un avertissement de GCC et Clang comme

prog.cc: In function 'int main()':
prog.cc:31:20: error: use of deleted function 'void Display(int, int, int)'
     Display(a, b, c);
                    ^
prog.cc:25:6: note: declared here
 void Display(int, int, int) = delete;

Vous faire connaître " vous faites quelque chose de mal, mais il ne peut le faire que s'il connaît les valeurs. Si vous avez

void Display(char a, char b, char c)
{
   cout << a << " " << b << " " << c << endl;
}

void Display(int, int, int) = delete;

int main()
{
    int a, b, c;
    std::cin >> a >> b >> c;
    Display(a, b, c);
    return 0;
}

Alors il ne sait pas quelles sont les valeurs donc il n'émettra pas d'avertissement.

Si vous voulez vraiment arrêter cela, vous pouvez ajouter une surcharge qui prend int s et le supprimer afin de provoquer une erreur du compilateur comme

int main()
{
    int a, b, c;
    std::cin >> a >> b >> c;
    Display(a, b, c);
    Display('a', 'b', 'c');

    return 0;
}

Erreur:

XXX

Vous pouvez également tout faire et utiliser

GCC
main.cpp:12:12: warning: overflow in conversion from 'int' to 'char' changes value from '2000' to ''\37777777720'' [-Woverflow]
    Display(2000, 32, 47);

Clang   
main.cpp:12:12: warning: implicit conversion from 'int' to 'char' changes value from 2000 to -48 [-Wconstant-conversion]
    Display(2000, 32, 47);

et cela fera de l'appel à Display une erreur avec n'importe quoi autre que 3 chars.


1 commentaires

Note aux futurs demandeurs: tenez compte des avertissements du compilateur. Ne les ignorez pas. Bien sûr, le programme se compile et s'exécute, mais l'avertissement est que le compilateur vous dit qu'il pourrait ne pas s'exécuter tout à fait comme prévu. Tirer parti des avertissements peut vous faire économiser beaucoup de débogage.